Files
TransPyC/lib/core/Handles/HandlesAssign.py
2026-06-16 16:09:42 +08:00

1658 lines
107 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo, FuncMeta
from lib.includes import t
import ast
import llvmlite.ir as ir
class AssignHandle:
def __init__(self, translator: "Translator"):
self.Trans = translator
self._CurrentCpythonObjectClass: str = None
@staticmethod
def _zero_value(var_type):
if isinstance(var_type, ir.ArrayType):
elem_zv = AssignHandle._zero_value(var_type.element)
if elem_zv is None:
return None
return ir.Constant(var_type, [elem_zv] * var_type.count)
elif isinstance(var_type, ir.IntType):
return ir.Constant(var_type, 0)
elif isinstance(var_type, (ir.FloatType, ir.DoubleType)):
return ir.Constant(var_type, 0.0)
elif isinstance(var_type, ir.PointerType):
return ir.Constant(var_type, None)
elif isinstance(var_type, ir.BaseStructType):
if var_type.elements is not None and len(var_type.elements) > 0:
elem_zvs = [AssignHandle._zero_value(m) for m in var_type.elements]
if any(zv is None for zv in elem_zvs):
return None
return ir.Constant(var_type, elem_zvs)
return None
return None
@staticmethod
def _contains_identified_struct(var_type):
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, VarType=None):
return self.Trans.ExprHandler.HandleExprLlvm(Node, VarType)
def _HandleAssignLlvm(self, Node):
Gen = self.Trans.LlvmGen
Gen._set_node_info(Node, "Assign")
if len(Node.targets) == 1:
Target = Node.targets[0]
if isinstance(Target, ast.Name):
VarName = Target.id
if VarName in Gen.var_const_flags:
src_info = Gen._get_node_info()
print(f"[错误] 不能对 const 变量 '{VarName}' 赋值{src_info}")
import sys
sys.exit(1)
if isinstance(Node.value, ast.Attribute) and isinstance(Node.value.value, ast.Name) and Node.value.value.id == 't':
AttrName = 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})
from lib.includes.t import CTypeRegistry
c_type_name = ''
resolved = CTypeRegistry.ResolveName(AttrName)
if resolved is not None:
ctype_cls, ptr_level = resolved
c_type_name = CTypeRegistry.CTypeToCName(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 = Gen._is_type_unsigned(c_type_name) if c_type_name else False
fmt_str = "%u\n" if is_unsigned else "%d\n"
fmt_bytes = fmt_str.encode('utf-8') + b'\x00'
fmt_type = ir.ArrayType(ir.IntType(8), len(fmt_bytes))
fmt_const = ir.Constant(fmt_type, bytearray(fmt_bytes))
fmt_gvar = ir.GlobalVariable(Gen.module, fmt_type, name=f"str_const_{Gen.string_const_counter}")
Gen.string_const_counter += 1
fmt_gvar.initializer = fmt_const
fmt_gvar.linkage = 'internal'
fmt_ptr = Gen.builder.bitcast(fmt_gvar, ir.PointerType(ir.IntType(8)), name=f"{VarName}_fmt")
fmt_var_name = f"__{VarName}_fmt"
if fmt_var_name not in Gen.variables:
fmt_alloca = Gen._alloca_entry(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 = f"__{VarName}_kind"
if kind_var_name not in Gen.variables:
kind_alloca = Gen._alloca_entry(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 = 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 = 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 = "%p\n"
fmt_bytes = fmt_str.encode('utf-8') + b'\x00'
fmt_type = ir.ArrayType(ir.IntType(8), len(fmt_bytes))
fmt_const = ir.Constant(fmt_type, bytearray(fmt_bytes))
fmt_gvar = ir.GlobalVariable(Gen.module, fmt_type, name=f"str_const_{Gen.string_const_counter}")
Gen.string_const_counter += 1
fmt_gvar.initializer = fmt_const
fmt_gvar.linkage = 'internal'
fmt_ptr = Gen.builder.bitcast(fmt_gvar, ir.PointerType(ir.IntType(8)), name=f"{VarName}_fmt")
fmt_var_name = f"__{VarName}_fmt"
if fmt_var_name not in Gen.variables:
fmt_alloca = Gen._alloca_entry(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 = f"__{VarName}_kind"
if kind_var_name not in Gen.variables:
kind_alloca = Gen._alloca_entry(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 = 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 = Gen._alloca_entry(ir.IntType(8).as_pointer(), name="va_list")
Gen.variables[VarName] = va_list_ptr
return
IsStructCtor = (isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name)
and Node.value.func.id in Gen.structs)
if IsStructCtor:
ClassName = Node.value.func.id
StructType = Gen.structs[ClassName]
IsUnion = False
if ClassName in self.Trans.SymbolTable:
TypeInfo = self.Trans.SymbolTable[ClassName]
if TypeInfo.IsUnion:
IsUnion = True
if IsUnion:
Value = self.HandleExprLlvm(Node.value)
if Value:
var = Gen._alloca_entry(Value.type, name=VarName)
Gen._store(Value, var)
Gen.variables[VarName] = var
return
ExistingPtr = None
if VarName in Gen.variables and Gen.variables[VarName] is not None:
VarPtr = Gen.variables[VarName]
if isinstance(VarPtr.type.pointee, ir.PointerType):
ExistingPtr = VarPtr
elif VarName in Gen._reg_values:
OldVal = Gen._reg_values[VarName]
if isinstance(OldVal.type, ir.PointerType):
var = Gen._alloca_entry(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 = Gen._direct_values.pop(VarName)
if isinstance(OldVal.type, ir.PointerType):
var = Gen._alloca_entry(OldVal.type, name=VarName)
Gen._store(OldVal, var)
Gen.variables[VarName] = var
ExistingPtr = var
if ExistingPtr:
pointee = ExistingPtr.type.pointee
if isinstance(pointee, ir.PointerType) and pointee.pointee == StructType:
self._InitStructAtPtr(Node.value, ClassName, ExistingPtr)
return
elif isinstance(pointee, ir.PointerType) and isinstance(pointee.pointee, ir.IntType) and pointee.pointee.width == 8:
self._InitStructAtPtr(Node.value, ClassName, ExistingPtr)
Gen.var_struct_class[VarName] = ClassName
return
if isinstance(Node.value, ast.Attribute):
enum_type_name = self._CheckEnumMemberAssignment(Node.value)
if enum_type_name:
Gen.var_type_info[VarName] = {'type': 'enum', 'name': enum_type_name}
var_type_for_list = None
if isinstance(Node.value, ast.List) and VarName in Gen.var_type_info:
type_info = Gen.var_type_info[VarName]
if type_info.get('type') == 'list':
var_type_for_list = type_info.get('full_type')
Value = self.HandleExprLlvm(Node.value, VarType=var_type_for_list)
if not Value:
return
if isinstance(Value.type, ir.VoidType):
return
Gen._unregister_temp_ptr(Value)
if isinstance(Value.type, ir.PointerType) and isinstance(Value.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
found_class = None
found = Gen.find_struct_by_pointee(Value.type.pointee)
if found:
CN, ST = found
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 = Value.type.pointee.name
for CN, ST in Gen.structs.items():
if isinstance(ST, ir.IdentifiedStructType) and ST.name == pointee_name:
found_class = CN
Gen.var_struct_class[VarName] = CN
Gen._var_to_heap_ptr[VarName] = Value
break
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 = Gen._alloca_entry(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 = Node.value.func.id
if call_func_name in Gen.var_type_info:
type_info = Gen.var_type_info[call_func_name]
if type_info['type'] in ('t_type', 'class_cast'):
src_fmt_var = f"__{call_func_name}_fmt"
dst_fmt_var = f"__{VarName}_fmt"
if src_fmt_var in Gen.variables:
if dst_fmt_var not in Gen.variables:
dst_alloca = Gen._alloca_entry(ir.PointerType(ir.IntType(8)), name=dst_fmt_var)
Gen.variables[dst_fmt_var] = dst_alloca
src_fmt_ptr = 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 = f"__{call_func_name}_kind"
dst_kind_var = f"__{VarName}_kind"
if src_kind_var in Gen.variables:
if dst_kind_var not in Gen.variables:
dst_kind_alloca = Gen._alloca_entry(ir.IntType(32), name=dst_kind_var)
Gen.variables[dst_kind_var] = dst_kind_alloca
src_kind_val = 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 = 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 = Gen.find_struct_by_pointee(Value.type.pointee)
if found:
CN, ST = found
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 = Gen._reg_values[VarName]
var = Gen._alloca_entry(OldVal.type, name=VarName)
Gen._store(OldVal, var)
Gen.variables[VarName] = var
del Gen._reg_values[VarName]
if VarName in Gen._direct_values:
OldVal = Gen._direct_values.pop(VarName)
var = Gen._alloca_entry(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 = Gen.variables[VarName]
TargetType = VarPtr.type.pointee if isinstance(VarPtr.type, ir.PointerType) else None
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 = Gen._load(Value, name=f"load_{VarName}")
try:
loaded_differ = TargetType and LoadedValue.type != TargetType
except AssertionError:
loaded_differ = False
if loaded_differ:
try:
Coerced = Gen._coerce_value(LoadedValue, TargetType)
if Coerced is not None:
LoadedValue = Coerced
except AssertionError:
pass
Gen._store(LoadedValue, VarPtr)
elif types_differ:
try:
Coerced = 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:
# 检查是否为模块级全局变量,避免创建局部变量遮蔽全局
if VarName in Gen.module.globals:
GVar = 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 = Gen._load(Value, name=f"load_{VarName}")
var = Gen._alloca_entry(LoadedValue.type, name=VarName)
Gen._store(LoadedValue, var)
Gen.variables[VarName] = var
else:
var = Gen._alloca_entry(Value.type, name=VarName)
Gen._store(Value, var)
Gen.variables[VarName] = var
is_u = 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 = Node.value.func.id
if call_func_name in Gen.var_type_info:
type_info = Gen.var_type_info[call_func_name]
if type_info['type'] in ('t_type', 'class_cast'):
src_fmt_var = f"__{call_func_name}_fmt"
dst_fmt_var = f"__{VarName}_fmt"
if src_fmt_var in Gen.variables:
if dst_fmt_var not in Gen.variables:
dst_alloca = Gen._alloca_entry(ir.PointerType(ir.IntType(8)), name=dst_fmt_var)
Gen.variables[dst_fmt_var] = dst_alloca
src_fmt_ptr = 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 = f"__{call_func_name}_kind"
dst_kind_var = f"__{VarName}_kind"
if src_kind_var in Gen.variables:
if dst_kind_var not in Gen.variables:
dst_kind_alloca = Gen._alloca_entry(ir.IntType(32), name=dst_kind_var)
Gen.variables[dst_kind_var] = dst_kind_alloca
src_kind_val = 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 = None
AttrName = Target.attr
VarName = None
if isinstance(Target.value, ast.Name):
VarName = Target.value.id
if 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:
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 = self.HandleExprLlvm(Node.value, VarType=TargetType)
if Value:
self._HandleAttributeStoreLlvm(Target, Value)
elif isinstance(Target, ast.Subscript):
TargetType = None
SubVarName = None
if isinstance(Target.value, ast.Name):
SubVarName = Target.value.id
if SubVarName in Gen.var_struct_class:
ClassName = 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 = 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 = 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 = var_val.type
if isinstance(var_type, ir.PointerType):
pointee = var_type.pointee
if isinstance(pointee, ir.ArrayType):
TargetType = pointee.element
elif isinstance(var_type, ir.ArrayType):
TargetType = var_type.element
Value = self.HandleExprLlvm(Node.value, VarType=TargetType)
if Value:
self._HandleSubscriptStoreLlvm(Target, Value)
elif isinstance(Target, ast.Tuple):
if isinstance(Node.value, ast.Call):
FuncName = None
module_path = 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
module_path = self.Trans.ExprCallHandle._get_module_path(Node.value.func.value)
CReturnTypes = []
FuncDef = 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 = 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 = Gen.functions.get(FuncName)
if func:
func_ft = getattr(func, 'ftype', None)
if func_ft:
ret_type = func_ft.return_type
if isinstance(ret_type, ir.LiteralStructType):
CReturnTypes = [None] * len(ret_type.elements)
if not CReturnTypes:
sym_key = FuncName
if sym_key not in self.Trans.SymbolTable:
if module_path:
sym_key = f"{module_path}.{FuncName}"
sym_info = self.Trans.SymbolTable.get(sym_key)
if sym_info and sym_info.IsFunction:
ret_type_info = getattr(sym_info, 'FuncPtrReturn', None)
param_type_infos = [pt for _, pt in getattr(sym_info, 'FuncPtrParams', [])]
if ret_type_info:
if isinstance(ret_type_info, CTypeInfo) and ret_type_info.BaseType:
ret_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 = []
for pt in param_type_infos:
if isinstance(pt, CTypeInfo) and pt.BaseType:
lp = 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(ret_type, llvm_param_types)
MangledName = Gen._mangle_func_name(FuncName)
func_decl = ir.Function(Gen.module, func_type, name=MangledName)
Gen.functions[MangledName] = func_decl
Gen.functions[FuncName] = func_decl
if not CReturnTypes and FuncName:
func = Gen.functions.get(FuncName)
if func:
func_ft = getattr(func, 'ftype', None)
if func_ft:
ret_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 = []
for arg in Node.value.args:
ArgVal = self.HandleExprLlvm(arg)
if ArgVal:
CallArgs.append(ArgVal)
for kw in Node.value.keywords:
pass
func = Gen.functions.get(FuncName)
func_ft = getattr(func, 'ftype', None) if func else None
func_params = list(getattr(func_ft, 'args', []) or []) if func_ft else []
while len(CallArgs) < len(func_params):
FuncDef = self.Trans.FunctionDefCache.get(FuncName)
if FuncDef and len(CallArgs) < len(FuncDef.args.args):
arg_def = FuncDef.args.defaults
arg_idx = len(CallArgs)
total_args = len(FuncDef.args.args)
default_start = total_args - len(arg_def)
if arg_idx >= default_start:
def_idx = arg_idx - default_start
if def_idx < len(arg_def):
DefVal = self.HandleExprLlvm(arg_def[def_idx])
if DefVal:
expected_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:
DefVal = Gen.builder.zext(DefVal, expected_type, name=f"zext_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 = Gen._adjust_args(CallArgs, func)
call_result = Gen.builder.call(func, adjusted, name=f"call_{FuncName}")
func_ft = getattr(func, 'ftype', None)
ret_type = getattr(func_ft, 'return_type', None) if func_ft else None
for j, elt in enumerate(Target.elts):
if isinstance(elt, ast.Name):
VarName = elt.id
field_val = Gen.builder.extract_value(call_result, j, name=f"extract_{FuncName}_{j}")
if CReturnTypes[j] is not None:
ReturnTypeInfo = 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 = 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 = 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, ClassName, VarPtr):
Gen = self.Trans.LlvmGen
if ClassName not in Gen.structs:
return
StructType = Gen.structs[ClassName]
StructPtrType = ir.PointerType(StructType)
RawPtr = Gen._load(VarPtr, name=getattr(VarPtr, 'name', 'ptr'))
StructPtr = Gen.builder.bitcast(RawPtr, StructPtrType, name=ClassName)
members = Gen.class_members.get(ClassName, [])
defaults = Gen.class_member_defaults.get(ClassName, {})
member_values = {}
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, _ = members[i]
val = self.HandleExprLlvm(arg)
if val:
member_values[member_name] = val
if call_node.keywords:
for kw in call_node.keywords:
val = self.HandleExprLlvm(kw.value)
if val:
member_values[kw.arg] = val
has_vtable = ClassName in Gen.class_vtable
base = 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 = 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 __import__('lib.constants.config', fromlist=['mode']).mode == "strict":
self.Trans.LogWarning(f"异常被忽略: {_e}")
InitFuncName = f'{ClassName}.__init__'
if Gen._has_function(InitFuncName):
Args = [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 _StoreOrStrCopy(self, VarName, VarPtr, Value):
Gen = self.Trans.LlvmGen
DestPtr = Gen._load(VarPtr, name=VarName)
if BaseHandle._is_char_pointer(DestPtr):
if BaseHandle._is_char_pointer(Value):
if 'strcpy' not in Gen.functions:
strcpy_type = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8))])
Gen.functions['strcpy'] = ir.Function(Gen.module, strcpy_type, name='strcpy')
Gen.builder.call(Gen.functions['strcpy'], [DestPtr, Value])
return
try:
CastedVal = Gen.builder.bitcast(Value, VarPtr.type.pointee, name=f"cast_{VarName}")
Gen._store(CastedVal, VarPtr)
except Exception: # 回退bitcast 失败时 alloca 新变量
NewVar = Gen._alloca_entry(Value.type, name=VarName)
Gen._store(Value, NewVar)
Gen.variables[VarName] = NewVar
def _HandleAttributeStoreLlvm(self, Target, Value):
Gen = self.Trans.LlvmGen
AttrName = Target.attr
if isinstance(Target.value, ast.Name) and Target.value.id == 'self':
ClassName = self.Trans._CurrentCpythonObjectClass
if ClassName and ClassName in Gen.structs:
PropKey = f'{ClassName}.{AttrName}'
PropInfo = self.Trans.SymbolTable.get(PropKey)
if PropInfo and hasattr(PropInfo, 'MetaList') and FuncMeta.PROPERTY_SETTER in PropInfo.MetaList:
SelfVar = Gen._get_var_ptr('self')
if SelfVar:
SelfPtr = Gen._load(SelfVar, name="self")
SetterFunc = Gen._get_function(PropKey)
if SetterFunc and SelfPtr:
Gen.builder.call(SetterFunc, [SelfPtr, Value], name=f"prop_set_{PropKey}")
return
SelfVar = Gen._get_var_ptr('self')
if not SelfVar:
return
if SelfVar:
SelfPtr = Gen._load(SelfVar, name="self")
is_vtable_method = False
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 = 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 = Gen.builder.gep(SelfPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"vtable_slot_{ClassName}")
VtablePtr = Gen._load(VtableSlotPtr, name=f"vtable_ptr_{ClassName}")
methods = Gen.class_methods[ClassName]
VtableArrayType = ir.ArrayType(ir.PointerType(ir.IntType(8)), len(methods))
ClassVtable = Gen.Vtables.get(ClassName)
if ClassVtable:
ClassVtableAddr = Gen.builder.bitcast(ClassVtable, ir.PointerType(ir.IntType(8)), name=f"class_vtable_addr_{ClassName}")
IsSameVtable = Gen.builder.icmp_unsigned('==', VtablePtr, ClassVtableAddr, name=f"is_same_vtable_{ClassName}")
CopyBlock = Gen.func.append_basic_block(name=f"vtable_copy_self_{AttrName}")
SkipBlock = Gen.func.append_basic_block(name=f"vtable_skip_self_{AttrName}")
Gen.builder.cbranch(IsSameVtable, CopyBlock, SkipBlock)
Gen.builder.position_at_end(CopyBlock)
if not hasattr(Gen, '_vtable_copy_counter'):
Gen._vtable_copy_counter = 0
Gen._vtable_copy_counter += 1
CopyName = f"{Gen._mangle_name(ClassName)}_vtable_copy_self_{Gen._vtable_copy_counter}"
VtableCopyGlobal = 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 = Gen.builder.bitcast(VtableCopyGlobal, ir.PointerType(ir.IntType(8)), name=f"vtable_copy_typed")
SrcTyped = Gen.builder.bitcast(ClassVtable, ir.PointerType(ir.IntType(8)), name=f"src_vtable_typed")
VtableSize = len(methods) * Gen.ptr_size
MemcpyFunc = Gen._find_function('llvm.memcpy.p0i8.p0i8.i64')
if not MemcpyFunc:
MemcpyType = 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 = 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 = Gen.builder.bitcast(VtablePtr, ir.PointerType(VtableArrayType), name=f"vtable_typed_{ClassName}")
MethodPtrAddr = Gen.builder.gep(VtableTyped, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), method_idx)], name=f"vmethod_slot_{AttrName}")
FuncPtrI8 = Gen.builder.bitcast(Value, ir.PointerType(ir.IntType(8)), name=f"func_ptr_i8_{AttrName}")
Gen._store(FuncPtrI8, MethodPtrAddr)
return
offset = Gen._get_member_offset(AttrName, ClassName)
struct_type = Gen.structs[ClassName]
max_offset = len(struct_type.elements) if isinstance(struct_type, ir.IdentifiedStructType) else 0
if offset >= max_offset:
VarName = f"self.{AttrName}"
if VarName not in Gen.variables:
NewVar = Gen._alloca_entry(Value.type, name=AttrName)
Gen.variables[VarName] = NewVar
Gen._store(Value, Gen.variables[VarName])
return
MemberPtr = 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 = Target.value.id
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:
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 = 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 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:
CN, ST = found
ClassName = CN
IsUnion = False
if ClassName and ClassName in self.Trans.SymbolTable:
TypeInfo = self.Trans.SymbolTable[ClassName]
if TypeInfo.IsUnion:
IsUnion = True
if ClassName and ClassName in Gen.structs:
PropKey = f'{ClassName}.{AttrName}'
PropInfo = self.Trans.SymbolTable.get(PropKey)
if PropInfo and hasattr(PropInfo, 'MetaList') and FuncMeta.PROPERTY_SETTER in PropInfo.MetaList:
ObjVal = self.Trans.ExprHandler.HandleExprLlvm(Target.value)
SetterFunc = Gen._get_function(PropKey)
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 = 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}")
if isinstance(ObjVal.type, ir.PointerType) and ObjVal.type.pointee == Gen.structs[ClassName]:
if IsUnion:
NestedStructName = f"{ClassName}_{AttrName}"
if NestedStructName in Gen.structs:
NestedStructType = Gen.structs[NestedStructName]
ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(NestedStructType), name=f"cast_{NestedStructName}")
offset = Gen._get_member_offset(AttrName, NestedStructName)
if offset is not None and offset < len(NestedStructType.elements):
MemberPtr = 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 = Gen.class_member_bitoffsets.get(ClassName, {})
if AttrName in bitfield_offsets:
self._store_bitfield_member(ObjVal, ClassName, AttrName, Value)
return
bitfields = 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 = 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 = False
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 = 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 = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"vtable_slot_{ClassName}")
VtablePtr = Gen._load(VtableSlotPtr, name=f"vtable_ptr_{ClassName}")
methods = Gen.class_methods[ClassName]
VtableArrayType = ir.ArrayType(ir.PointerType(ir.IntType(8)), len(methods))
ClassVtable = Gen.Vtables.get(ClassName)
if ClassVtable:
ClassVtableAddr = Gen.builder.bitcast(ClassVtable, ir.PointerType(ir.IntType(8)), name=f"class_vtable_addr_{ClassName}")
IsSameVtable = Gen.builder.icmp_unsigned('==', VtablePtr, ClassVtableAddr, name=f"is_same_vtable_{ClassName}")
CopyBlock = Gen.func.append_basic_block(name=f"vtable_copy_{AttrName}")
SkipBlock = Gen.func.append_basic_block(name=f"vtable_skip_{AttrName}")
Gen.builder.cbranch(IsSameVtable, CopyBlock, SkipBlock)
Gen.builder.position_at_end(CopyBlock)
if not hasattr(Gen, '_vtable_copy_counter'):
Gen._vtable_copy_counter = 0
Gen._vtable_copy_counter += 1
CopyName = f"{Gen._mangle_name(ClassName)}_vtable_copy_{Gen._vtable_copy_counter}"
VtableCopyGlobal = 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 = Gen.builder.bitcast(VtableCopyGlobal, ir.PointerType(ir.IntType(8)), name=f"vtable_copy_typed")
SrcTyped = Gen.builder.bitcast(ClassVtable, ir.PointerType(ir.IntType(8)), name=f"src_vtable_typed")
VtableSize = len(methods) * Gen.ptr_size
MemcpyFunc = Gen._find_function('llvm.memcpy.p0i8.p0i8.i64')
if not MemcpyFunc:
MemcpyType = 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 = 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 = Gen.builder.bitcast(VtablePtr, ir.PointerType(VtableArrayType), name=f"vtable_typed_{ClassName}")
MethodPtrAddr = Gen.builder.gep(VtableTyped, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), method_idx)], name=f"vmethod_slot_{AttrName}")
FuncPtrI8 = Gen.builder.bitcast(Value, ir.PointerType(ir.IntType(8)), name=f"func_ptr_i8_{AttrName}")
Gen._store(FuncPtrI8, MethodPtrAddr)
return
offset = Gen._get_member_offset(AttrName, ClassName)
StructType = 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
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:
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 = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName)
else:
return
byte_order = getattr(Gen, 'class_member_byteorders', {}).get(ClassName, {}).get(AttrName, "")
if byte_order == 'big':
st = Gen.structs.get(ClassName)
if st is None or st.elements is None or len(st.elements) == 0:
return
member_type = st.elements[offset]
if isinstance(member_type, ir.IntType):
if member_type.width == 16:
Value = Gen.builder.bswap(Value, name=f"bswap_store_{AttrName}")
elif member_type.width == 32:
Value = Gen.builder.bswap(Value, name=f"bswap_store_{AttrName}")
elif member_type.width == 64:
Value = Gen.builder.bswap(Value, name=f"bswap_store_{AttrName}")
self._StoreWithCoerce(Value, MemberPtr)
if not ClassName:
imported_modules = getattr(self.Trans, '_imported_modules', None)
import_aliases = getattr(self.Trans, '_import_aliases', {})
resolved_mod = import_aliases.get(VarName, VarName)
if imported_modules and (VarName in imported_modules or resolved_mod in imported_modules):
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
if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
return
self._StoreWithCoerce(Value, GVar)
return
module_sha1_map = getattr(Gen, 'module_sha1_map', {})
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 = module_sha1_map.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
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 = self.Trans.ExprHandler.HandleExprLlvm(Target.value)
if ObjVal and isinstance(ObjVal.type, ir.PointerType):
pointee = 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 = 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 = Gen.class_member_bitoffsets.get(CN, {})
if AttrName in bitfield_offsets:
self._store_bitfield_member(ObjVal, CN, AttrName, Value)
return
offset = Gen._get_member_offset(AttrName, CN)
if offset is not None and ST.elements is not None and offset < len(ST.elements):
MemberPtr = 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 = None
for CN in Gen.class_members:
members = 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 = 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 = Gen._get_member_offset(AttrName, matched_cn)
if offset is not None and ST.elements is not None and offset < len(ST.elements):
MemberPtr = 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 = None
is_cderef = (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 = Target.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.Trans.ExprHandler.HandleExprLlvm(Target.value)
if ObjVal and isinstance(ObjVal.type, ir.PointerType):
pointee = 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 = Gen.class_member_bitoffsets.get(CN, {})
if AttrName in bitfield_offsets:
self._store_bitfield_member(ObjVal, CN, AttrName, Value)
return
offset = Gen._get_member_offset(AttrName, CN)
if offset is not None and ST.elements is not None and offset < len(ST.elements):
MemberPtr = 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 = self.Trans.ExprAttrHandle.HandleSubscriptPtrLlvm(Target.value)
if SubPtr and isinstance(SubPtr.type, ir.PointerType):
pointee = SubPtr.type.pointee
if isinstance(Target.value.value, ast.Attribute):
AttrNameSub = Target.value.value.attr
if AttrNameSub == 'items' and 'Item' in Gen.structs:
ObjValCast = Gen.builder.bitcast(SubPtr, ir.PointerType(Gen.structs['Item']), name=f"cast_Item")
offset = Gen._get_member_offset(AttrName, 'Item')
MemberPtr = 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 = Gen.builder.bitcast(SubPtr, ir.PointerType(ST), name=f"cast_{CN}")
offset = Gen._get_member_offset(AttrName, CN)
MemberPtr = 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 = 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(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 = Gen._get_member_offset(AttrName, CN)
if offset is not None and ST.elements is not None and offset < len(ST.elements):
MemberPtr = 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 = Gen._load(SubPtr, name=f"load_{AttrName}_ptr")
if isinstance(LoadedPtr.type, ir.PointerType) and isinstance(LoadedPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
found = Gen.find_struct_by_pointee(LoadedPtr.type.pointee)
if found:
CN, ST = found
offset = Gen._get_member_offset(AttrName, CN)
MemberPtr = Gen.builder.gep(LoadedPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName)
self._StoreWithCoerce(Value, MemberPtr)
def _HandleSubscriptStoreLlvm(self, Target, Value):
Gen = self.Trans.LlvmGen
if isinstance(Target.value, ast.Name):
SubVarName = Target.value.id
if SubVarName in Gen.var_const_flags:
src_info = Gen._get_node_info()
self.Trans.LogError(f"不能对 const 变量 '{SubVarName}' 的元素赋值{src_info}")
ClassName = self.Trans.ExprHandler._get_var_class(Target.value, Gen)
if ClassName and Gen._has_function(f'{ClassName}.__setitem__'):
obj_val = self.Trans.ExprHandler.HandleExprLlvm(Target.value)
idx_val = self.Trans.ExprHandler.HandleExprLlvm(Target.slice)
if obj_val and idx_val:
if BaseHandle._is_char_pointer(obj_val):
obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
Gen.builder.call(Gen._get_function(f'{ClassName}.__setitem__'), [obj_val, idx_val, Value], name=f"call_{ClassName}.__setitem__")
return
ValueVal = self.HandleExprLlvm(Target.value)
IndexVal = self.HandleExprLlvm(Target.slice)
if not ValueVal or not IndexVal:
return
if BaseHandle._is_char_pointer(IndexVal):
loaded_byte = 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 = self._get_int_ptr(Target.value)
if var_ptr:
i8_ptr = 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 = 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 = Gen.builder.gep(ValueVal, [IndexVal], name="subscript")
self._StoreWithCoerce(Value, ElemPtr)
return
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")
else:
ElemPtr = Gen.builder.gep(ValueVal, [IndexVal], name="subscript")
self._StoreWithCoerce(Value, ElemPtr)
elif isinstance(ValueVal.type, ir.ArrayType):
zero = ir.Constant(ir.IntType(32), 0)
if isinstance(Target.value, ast.Name):
VarName = Target.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")
self._StoreWithCoerce(Value, ElemPtr)
return
if isinstance(Target.value, ast.Subscript):
InnerPtr = 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 = Gen.builder.gep(InnerPtr, [zero, IndexVal], name="subscript")
self._StoreWithCoerce(Value, ElemPtr)
return
if isinstance(Target.value, ast.Attribute):
AttrPtr = 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 = Gen.builder.gep(AttrPtr, [zero, IndexVal], name="subscript")
self._StoreWithCoerce(Value, ElemPtr)
return
arr_alloc = Gen._alloca_entry(ValueVal.type, name="arr_subscript_tmp")
Gen._store(ValueVal, arr_alloc)
ElemPtr = Gen.builder.gep(arr_alloc, [zero, IndexVal], name="subscript")
self._StoreWithCoerce(Value, ElemPtr)
ModifiedArr = Gen._load(arr_alloc, name="modified_arr")
if isinstance(Target.value, ast.Subscript):
OuterPtr = self.Trans.ExprAttrHandle.HandleSubscriptPtrLlvm(Target.value)
if OuterPtr:
Gen._store(ModifiedArr, OuterPtr)
elif isinstance(Target.value, ast.Attribute):
OuterPtr = self.Trans.ExprAttrHandle._get_attr_ptr(Target.value)
if OuterPtr:
Gen._store(ModifiedArr, OuterPtr)
def _StoreWithCoerce(self, Value, Ptr):
Gen = self.Trans.LlvmGen
if isinstance(Ptr.type, ir.PointerType):
TargetType = Ptr.type.pointee
if Value.type != TargetType:
if isinstance(TargetType, ir.ArrayType) and isinstance(Value.type, ir.PointerType):
ElemType = TargetType.element
ElemSize = Gen._get_struct_size(ElemType)
for i in range(TargetType.count):
DstElem = Gen.builder.gep(Ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), i)], name=f"arr_dst_{i}")
if ElemSize == 1:
SrcPtr = Gen.builder.gep(Value, [ir.Constant(ir.IntType(32), i)], name=f"arr_src_{i}")
else:
PtrInt = Gen.builder.ptrtoint(Value, ir.IntType(64))
Offset = ir.Constant(ir.IntType(64), i * ElemSize)
NewPtrInt = Gen.builder.add(PtrInt, Offset)
SrcPtr = Gen.builder.inttoptr(NewPtrInt, ir.PointerType(ElemType), name=f"arr_src_{i}")
SrcVal = 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 = Gen._coerce_value(Value, TargetType)
if Coerced is not None:
Value = Coerced
Gen._store(Value, Ptr)
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 None
def _EmitGlobalAnnAssignLlvm(self, Node, Gen):
if isinstance(Node.target, ast.Name):
VarName = Node.target.id
EffectiveAnnotation = Node.annotation
if VarName in self.Trans.SymbolTable:
Info = self.Trans.SymbolTable[VarName]
if Info.get('type') == 'typedef':
return
if isinstance(EffectiveAnnotation, ast.BinOp) and isinstance(EffectiveAnnotation.op, ast.BitOr):
for side in [EffectiveAnnotation.left, EffectiveAnnotation.right]:
if isinstance(side, ast.Subscript) and isinstance(side.value, ast.Name) and side.value.id == 'list':
EffectiveAnnotation = side
break
if isinstance(EffectiveAnnotation, ast.Subscript) and isinstance(EffectiveAnnotation.value, ast.Name) and EffectiveAnnotation.value.id == 'list':
slice_node = EffectiveAnnotation.slice
if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2:
elem_type_node = slice_node.elts[0]
count_node = slice_node.elts[1]
if isinstance(elem_type_node, ast.Name) and elem_type_node.id in Gen.structs:
SymEntry = self.Trans.SymbolTable.get(elem_type_node.id)
if SymEntry and isinstance(SymEntry, CTypeInfo) and SymEntry.IsFuncPtr:
ElemType = ir.IntType(8).as_pointer()
else:
ElemType = Gen.structs[elem_type_node.id]
else:
ElemTypeInfo = CTypeInfo.FromNode(elem_type_node, self.Trans.SymbolTable)
if ElemTypeInfo and ElemTypeInfo.IsFuncPtr:
ElemType = ir.IntType(8).as_pointer()
else:
if ElemTypeInfo is None:
ElemTypeInfo = CTypeInfo()
ElemTypeInfo.BaseType = t.CInt()
ElemType = Gen._ctype_to_llvm(ElemTypeInfo)
if isinstance(ElemType, ir.VoidType):
ElemType = ir.IntType(32)
ArrayCount = 1
if isinstance(count_node, ast.Constant) and isinstance(count_node.value, int):
ArrayCount = count_node.value
elif isinstance(count_node, ast.Name):
if count_node.id in self.Trans.SymbolTable:
SymInfo = self.Trans.SymbolTable[count_node.id]
if isinstance(getattr(SymInfo, 'value', None), int):
ArrayCount = SymInfo.value
if ArrayCount == 1 and count_node.id in getattr(Gen, '_define_constants', {}):
DefVal = Gen._define_constants[count_node.id]
if isinstance(DefVal, int):
ArrayCount = DefVal
elif isinstance(count_node, ast.Attribute):
ev = self._eval_global_count(count_node, Gen)
if ev is not None:
ArrayCount = ev
elif isinstance(count_node, ast.BinOp):
ev = self._eval_global_count(count_node, Gen)
if ev is not None:
ArrayCount = ev
elif count_node is None or (isinstance(count_node, ast.Constant) and count_node.value is None):
if Node.value and isinstance(Node.value, ast.List):
ArrayCount = len(Node.value.elts)
elif Node.value and isinstance(Node.value, ast.Constant) and isinstance(Node.value.value, str):
ArrayCount = len(Node.value.value) + 1
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 = Node.value.value + '\x00'
str_bytes = 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 = self._zero_value(VarType)
else:
InitConstants = self.Trans._BuildArrayInitConstants(Node.value, ElemType, elem_type_node, ArrayCount, Gen)
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(EffectiveAnnotation, ast.Subscript) and isinstance(EffectiveAnnotation.value, ast.Name) and EffectiveAnnotation.value.id == 'list':
slice_node = EffectiveAnnotation.slice
elem_type_node = slice_node
if isinstance(elem_type_node, ast.Name) and elem_type_node.id in Gen.structs:
ElemType = Gen.structs[elem_type_node.id]
else:
ElemTypeInfo = CTypeInfo.FromNode(elem_type_node, self.Trans.SymbolTable)
if ElemTypeInfo is None:
ElemTypeInfo = CTypeInfo()
ElemTypeInfo.BaseType = t.CInt()
ElemType = Gen._ctype_to_llvm(ElemTypeInfo)
if isinstance(ElemType, ir.VoidType):
ElemType = ir.IntType(32)
VarType = ir.PointerType(ElemType)
if VarName not in Gen.variables and VarName not in Gen.module.globals:
GlobalVar = 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
if isinstance(Node.annotation, ast.Name) and Node.annotation.id in Gen.structs:
StructName = Node.annotation.id
VarType = Gen.structs[StructName]
if VarName not in Gen.variables and VarName not in Gen.module.globals:
GlobalVar = 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 = 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.FromNode(Node.annotation, self.Trans.SymbolTable)
if not TypeInfo or not TypeInfo.BaseType:
ArrayTypeInfo = CTypeInfo._HandleArraySubscript(Node.annotation, self.Trans.SymbolTable)
if ArrayTypeInfo:
TypeInfo = ArrayTypeInfo
IsCDefine = 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 = self.Trans.TypeMergeHandler.GetCTypeInfo(Node.annotation)
if TTypeInfo:
TTypeInfo.IsTypedef = True
TTypeInfo.Name = VarName
self.Trans.SymbolTable[VarName] = TTypeInfo
if IsCDefine:
if Node.value:
define_constants = vars(Gen).setdefault('_define_constants', {})
try:
const_value = self._eval_const_expr(Node.value, Gen)
if const_value is not None:
define_constants[VarName] = const_value
except Exception as _e:
if __import__('lib.constants.config', fromlist=['mode']).mode == "strict":
self.Trans.LogWarning(f"异常被忽略: {_e}")
return
if TypeInfo is None:
TypeInfo = CTypeInfo()
TypeInfo.BaseType = t.CInt()
VarType = 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:
return
if isinstance(VarType, (ir.IdentifiedStructType, ir.LiteralStructType)):
GlobalVar = 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(Gen.module, VarType, name=VarName)
if Node.value:
if isinstance(Node.value, ast.Constant) and isinstance(Node.value.value, str) and isinstance(VarType, ir.PointerType):
str_val = Node.value.value + '\x00'
str_bytes = str_val.encode('utf-8')
arr_type = ir.ArrayType(ir.IntType(8), len(str_bytes))
str_gv_name = VarName + '_str'
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.IntType(8))
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
else:
if isinstance(VarType, ir.ArrayType) and isinstance(Node.value, (ast.List, ast.Set)):
InitConstants = 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 = self._zero_value(VarType)
if zv:
GlobalVar.initializer = zv
else:
GlobalVar.linkage = 'common'
else:
init_val = 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 = self._zero_value(VarType)
else:
if isinstance(VarType, ir.BaseStructType) or self._contains_identified_struct(VarType):
GlobalVar.linkage = 'common'
else:
GlobalVar.initializer = self._zero_value(VarType)
Gen.variables[VarName] = GlobalVar
def _eval_global_const(self, value_node, var_type, Gen):
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 = 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 = self._eval_global_const(value_node.operand, var_type, Gen)
if inner:
return ir.Constant(var_type, -inner.constant)
return None
def _eval_type_ctor_const(self, call_node, var_type, Gen):
"""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 = call_node.args[0]
# Recursively evaluate the argument as a constant
arg_val = 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, ClassName, field_name, Value):
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 False
bit_offset = bitfield_offsets[field_name]
bit_width = bitfield_widths.get(field_name, 0)
if bit_width == 0:
return False
struct_type = 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 = 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")
old_val = Gen._load(member_ptr, name=f"{field_name}_old_storage")
mask = (1 << bit_width) - 1
shifted_mask = mask << bit_offset
inverted_mask = ir.Constant(storage_type, ~shifted_mask & ((1 << storage_type.width) - 1))
cleared = 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 = Gen.builder.shl(Value, ir.Constant(storage_type, bit_offset), name=f"{field_name}_shift_store")
masked_value = Gen.builder.and_(shifted_value, ir.Constant(storage_type, shifted_mask), name=f"{field_name}_mask_store")
new_val = Gen.builder.or_(cleared, masked_value, name=f"{field_name}_new_storage")
Gen._store(new_val, member_ptr)
return True
def _CheckEnumMemberAssignment(self, node):
def _get_attr_path(n):
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 = _get_attr_path(node)
if not attr_path:
return None
parts = attr_path.split('.')
if len(parts) >= 2:
enum_class_name = parts[-2]
member_name = parts[-1]
qualified_name = f"{enum_class_name}.{member_name}"
if qualified_name in self.Trans.SymbolTable:
info = self.Trans.SymbolTable[qualified_name]
if info.IsEnumMember and info.EnumName:
return info.EnumName
under_name = f"{enum_class_name}_{member_name}"
if under_name in self.Trans.SymbolTable:
info = 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 = 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):
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, Gen):
if len(Node.targets) == 1 and isinstance(Node.targets[0], ast.Name):
VarName = 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 = Node.value.func.id
if FuncName in Gen.structs:
IsUnion = False
if FuncName in self.Trans.SymbolTable:
TypeInfo = self.Trans.SymbolTable[FuncName]
if TypeInfo.IsUnion:
IsUnion = True
if IsUnion:
StructType = Gen.structs[FuncName]
StructPtrType = ir.PointerType(StructType)
GlobalVar = 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 = FuncName
VarType = Gen.structs[StructName]
GlobalVar = ir.GlobalVariable(Gen.module, VarType, name=VarName)
const = 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(Gen.module, ir.IntType(32), name=VarName)
init_val = 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, Gen):
"""计算常量表达式的值"""
import ast
if isinstance(node, ast.Constant):
return node.value
elif isinstance(node, ast.BinOp):
left = self._eval_const_expr(node.left, Gen)
right = self._eval_const_expr(node.right, Gen)
if left is None or right is None:
return None
if isinstance(node.op, ast.Add):
return left + right
elif isinstance(node.op, ast.Sub):
return left - right
elif isinstance(node.op, ast.Mult):
return left * right
elif isinstance(node.op, ast.Div):
return left // right if isinstance(left, int) and isinstance(right, int) else left / right
elif isinstance(node.op, ast.FloorDiv):
return left // right
elif isinstance(node.op, ast.Mod):
return left % right
elif isinstance(node.op, ast.Pow):
return left ** right
elif isinstance(node.op, ast.LShift):
return left << right
elif isinstance(node.op, ast.RShift):
return left >> right
elif isinstance(node.op, ast.BitOr):
return left | right
elif isinstance(node.op, ast.BitXor):
return left ^ right
elif isinstance(node.op, ast.BitAnd):
return left & right
elif isinstance(node, ast.UnaryOp):
operand = self._eval_const_expr(node.operand, Gen)
if operand is None:
return None
if isinstance(node.op, ast.USub):
return -operand
elif isinstance(node.op, ast.UAdd):
return +operand
elif isinstance(node.op, ast.Invert):
return ~operand
elif isinstance(node, ast.Name):
if node.id in getattr(Gen, '_define_constants', {}):
return Gen._define_constants[node.id]
if node.id in self.Trans.SymbolTable:
SymInfo = self.Trans.SymbolTable[node.id]
val = getattr(SymInfo, 'value', None)
if isinstance(val, (int, float)):
return val
if getattr(SymInfo, 'IsDefine', None) and isinstance(getattr(SymInfo, 'DefineValue', None), (int, float)):
return SymInfo.DefineValue
elif isinstance(node, ast.Attribute):
module_name = node.value.id if isinstance(node.value, ast.Name) else None
attr_name = node.attr
if module_name and attr_name:
combined_key = f"{module_name}.{attr_name}"
if combined_key in getattr(Gen, '_define_constants', {}):
val = Gen._define_constants[combined_key]
if isinstance(val, (int, float)):
return int(val) if isinstance(val, float) and val == int(val) else val
for key, SymInfo in self.Trans.SymbolTable.items():
if key.endswith(f".{combined_key}") or key == combined_key:
if getattr(SymInfo, 'IsDefine', None) and isinstance(getattr(SymInfo, 'DefineValue', None), (int, float)):
return int(SymInfo.DefineValue) if isinstance(SymInfo.DefineValue, float) and SymInfo.DefineValue == int(SymInfo.DefineValue) else SymInfo.DefineValue
all_dc = getattr(self.Trans, '_all_define_constants', None) or getattr(Gen, '_all_define_constants', {})
if combined_key in all_dc:
val = all_dc[combined_key]
if isinstance(val, (int, float)):
return int(val) if isinstance(val, float) and val == int(val) else val
if attr_name in all_dc:
val = all_dc[attr_name]
if isinstance(val, (int, float)):
return int(val) if isinstance(val, float) and val == int(val) else val
for dc_key, dc_val in all_dc.items():
if dc_key == attr_name or dc_key.endswith(f".{attr_name}"):
if isinstance(dc_val, (int, float)):
return int(dc_val) if isinstance(dc_val, float) and dc_val == int(dc_val) else dc_val
if attr_name in self.Trans.SymbolTable:
SymInfo = self.Trans.SymbolTable[attr_name]
if getattr(SymInfo, 'IsDefine', None) and isinstance(getattr(SymInfo, 'DefineValue', None), (int, float)):
return int(SymInfo.DefineValue) if isinstance(SymInfo.DefineValue, float) and SymInfo.DefineValue == int(SymInfo.DefineValue) else SymInfo.DefineValue
if attr_name in getattr(Gen, '_define_constants', {}):
val = Gen._define_constants[attr_name]
if isinstance(val, (int, float)):
return int(val) if isinstance(val, float) and val == int(val) else val
return None
def _eval_global_count(self, node, Gen):
val = 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