Files
TransPyC/lib/core/Handles/HandlesAssign.py

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