c 类(源码违规):这些变量由 new_param_node 构造、或取自 get_struct_fields / param_list_append / function_get_param_head,实际是 llvmlite.ParamNode 链节点, 注解却写成 llvmlite.Function*。旧的无条件指针 bitcast 掩盖了该错误,严格指针规则下暴露。 涉及:VarGenMixin / CallGenVt / VpiReader / ClassGenEnum / ClassGenVTable / ExprGenName / FuncGenMixin / FuncGenDef / TypeGenResolve / TypeSpec / StmtGenCifMixin / AssignGenMixin(纯注解替换,零语义变化)。15 行。
177 lines
10 KiB
Plaintext
177 lines
10 KiB
Plaintext
import t, c
|
||
from stdint import *
|
||
import ast
|
||
import llvmlite
|
||
import memhub
|
||
import string
|
||
import viperlib
|
||
import lib.core.Gen.Translator as HT
|
||
import lib.core.Gen.GenTypes as GenTypes
|
||
|
||
from . import CallGenBase
|
||
|
||
|
||
# ============================================================
|
||
# CallGenVt - CallGenMixin 拆分(阶段 B):vtable 槽位写入
|
||
# ============================================================
|
||
novirtual class CallGenVt(CallGenBase.CallGenBase):
|
||
"""vtable 槽位写入"""
|
||
|
||
# _write_vtable_slot / _write_vtable_attr:把模块级函数指针写入对象 vtable 的方法槽位(devfs 驱动注册模式,对齐 TPC HandlesAssign.py L905-949 写时复制)——vtable 方法不是数据字段,get_attribute_ptr 查不到;对象 vtable 仍指向类默认 vtable 时先复制一份(internal 全局 + llvm.memcpy)并让对象指向副本,再 GEP method_index 槽位 store i8*。多次写入互不覆盖
|
||
|
||
# ============================================================
|
||
def _write_vtable_slot(self, pool: memhub.MemBuddy*,
|
||
builder: llvmlite.IRBuilder*,
|
||
mod: llvmlite.LLVMModule*,
|
||
obj_ptr: llvmlite.Value*,
|
||
class_name: str,
|
||
method_index: int,
|
||
func_val: llvmlite.Value*,
|
||
trans: HT.Translator*) -> int:
|
||
"""生成 vtable 槽位写入(写时复制),成功返回 1"""
|
||
if pool is None or builder is None or mod is None or trans is None: return 0
|
||
if obj_ptr is None or class_name is None or func_val is None: return 0
|
||
if method_index < 0 or trans._cur_func is None: return 0
|
||
i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool)
|
||
if i8_ty is None: return 0
|
||
i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty)
|
||
if i8_ptr_ty is None: return 0
|
||
i8_ptr_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ptr_ty)
|
||
if i8_ptr_ptr_ty is None: return 0
|
||
method_count: int = self.Gen.StructGen.get_vtable_method_count(class_name)
|
||
if method_count <= 0: return 0
|
||
# 构造 vtable 类型 { i8*, i8*, ... }
|
||
# vtable 类型的字段链表是 llvmlite.ParamNode(new_param_node / paramnode_set_next /
|
||
# Struct 形参均为 rawptr[ParamNode])——原先误注解为 Function*。
|
||
vt_first: llvmlite.ParamNode* = None
|
||
vt_prev: llvmlite.ParamNode* = None
|
||
for vi in range(method_count):
|
||
pn: llvmlite.ParamNode* = llvmlite.new_param_node(pool, i8_ptr_ty)
|
||
if pn is None: continue
|
||
if vt_first is None:
|
||
vt_first = pn
|
||
if vt_prev is not None:
|
||
llvmlite.paramnode_set_next(vt_prev, pn)
|
||
vt_prev = pn
|
||
vtable_ty: llvmlite.LLVMType* = llvmlite.Struct(pool, vt_first, method_count, None)
|
||
if vtable_ty is None:
|
||
return 0
|
||
# 对象 vtable 槽位(对象头 → i8**,vtable 指针总是第一个字段)
|
||
vtable_slot: llvmlite.Value* = llvmlite.build_bitcast(builder, obj_ptr, i8_ptr_ptr_ty)
|
||
if vtable_slot is None: return 0
|
||
vtable_ptr: llvmlite.Value* = llvmlite.build_load(builder, i8_ptr_ty, vtable_slot)
|
||
if vtable_ptr is None: return 0
|
||
# 类默认 vtable 地址(比较用)
|
||
class_vt: llvmlite.Value* = self.Gen.CallGenLeafKit._make_vtable_ref_i8(pool, builder, mod, class_name, trans)
|
||
if class_vt is None: return 0
|
||
cmp_vt: llvmlite.Value* = llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, vtable_ptr, class_vt)
|
||
if cmp_vt is None: return 0
|
||
# 块名唯一化(create_block 不自动编号;同函数多次 vtable 写入(如
|
||
# devfs open/close/read/write 连续赋值)同名 label 冲突)
|
||
vtc3: int = trans._label_counter
|
||
trans._label_counter = vtc3 + 1
|
||
vt_bb_buf3: str = pool.alloc(64)
|
||
if vt_bb_buf3 is None: return 0
|
||
viperlib.snprintf(vt_bb_buf3, 64, "vt.copy.%d", vtc3)
|
||
vt_copy_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, trans._cur_func, vt_bb_buf3)
|
||
viperlib.snprintf(vt_bb_buf3, 64, "vt.skip.%d", vtc3)
|
||
vt_skip_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, trans._cur_func, vt_bb_buf3)
|
||
if vt_copy_bb is None or vt_skip_bb is None: return 0
|
||
llvmlite.build_cond_br(builder, cmp_vt, vt_copy_bb, vt_skip_bb)
|
||
# copy 块:创建 internal 副本全局(zeroinit)+ memcpy + 对象指向副本
|
||
llvmlite.position_at_end(builder, vt_copy_bb)
|
||
vtc: int = trans._label_counter
|
||
trans._label_counter = vtc + 1
|
||
vcopy_buf: str = pool.alloc(256)
|
||
if vcopy_buf is not None:
|
||
viperlib.snprintf(vcopy_buf, 256, "%s.vtable.copy.%d", class_name, vtc)
|
||
vcopy_gv: llvmlite.GlobalVariable* = llvmlite.new_global_variable(pool, vcopy_buf, vtable_ty)
|
||
if vcopy_gv is not None:
|
||
llvmlite.module_add_global(mod, vcopy_gv)
|
||
vcopy_gv.Linkage = None
|
||
vcopy_gv.Initializer = "zeroinitializer"
|
||
# 引用名必须带 @ 前缀:SSAValue 名原样输出,裸名
|
||
# devfs_file.vtable.copy.71 无 @ → llc "expected value token"
|
||
# (devfs vtable.copy 根因;全局定义 @name 是 new_global_variable
|
||
# 输出时加的,引用侧不自动加)
|
||
vcopy_ref_nm: str = pool.alloc(272)
|
||
if vcopy_ref_nm is None:
|
||
vcopy_ref_nm = vcopy_buf
|
||
else:
|
||
viperlib.snprintf(vcopy_ref_nm, 272, "@%s", vcopy_buf)
|
||
vcopy_ref: llvmlite.Value* = llvmlite.SSAValue(pool, llvmlite.Ptr(pool, vtable_ty), vcopy_ref_nm)
|
||
if vcopy_ref is not None:
|
||
vcopy_i8: llvmlite.Value* = llvmlite.build_bitcast(builder, vcopy_ref, i8_ptr_ty)
|
||
if vcopy_i8 is not None:
|
||
# ConstInt 的 name 必须是数字文本(如 "56"),不能是
|
||
# 标识符 "vtsz"——参数经 Name 原样输出,裸名 vtsz 无 %
|
||
# → llc "expected value token"(devfs memcpy 根因)
|
||
vtsz_buf: str = pool.alloc(32)
|
||
if vtsz_buf is not None:
|
||
viperlib.snprintf(vtsz_buf, 32, "%lld", method_count * 8)
|
||
vt_size: llvmlite.Value* = llvmlite.ConstInt(pool, llvmlite.Int64(pool), method_count * 8, vtsz_buf)
|
||
if vt_size is not None:
|
||
self.Gen.CallGenLib._emit_llvm_memcpy_intrinsic(pool, builder, mod, vcopy_i8, class_vt, vt_size)
|
||
llvmlite.build_store(builder, vcopy_i8, vtable_slot)
|
||
llvmlite.build_br(builder, vt_skip_bb)
|
||
# skip 块:reload vtable → GEP 槽位 → store 函数指针(i8*)
|
||
llvmlite.position_at_end(builder, vt_skip_bb)
|
||
vt_ptr2: llvmlite.Value* = llvmlite.build_load(builder, i8_ptr_ty, vtable_slot)
|
||
if vt_ptr2 is None: return 0
|
||
vt_typed: llvmlite.Value* = llvmlite.build_bitcast(builder, vt_ptr2, llvmlite.Ptr(pool, vtable_ty))
|
||
if vt_typed is None: return 0
|
||
vt_slotp: llvmlite.Value* = llvmlite.build_gep_struct(builder, vtable_ty, i8_ptr_ty, vt_typed, method_index)
|
||
if vt_slotp is None: return 0
|
||
fptr_i8: llvmlite.Value* = llvmlite.build_bitcast(builder, func_val, i8_ptr_ty)
|
||
if fptr_i8 is not None:
|
||
llvmlite.build_store(builder, fptr_i8, vt_slotp)
|
||
return 1
|
||
def _write_vtable_attr(self, builder: llvmlite.IRBuilder*,
|
||
pool: memhub.MemBuddy*,
|
||
mod: llvmlite.LLVMModule*,
|
||
node: ast.AST*,
|
||
rhs_val: llvmlite.Value*,
|
||
trans: HT.Translator*) -> int:
|
||
"""属性写入 obj.method = func:检测 vtable 方法并生成槽位写入(成功返回 1)"""
|
||
if node is None or builder is None or pool is None or mod is None: return 0
|
||
if rhs_val is None or trans is None: return 0
|
||
at: ast.Attribute* = ast.Attribute*(node)
|
||
if at is None or at.value is None or at.attr is None: return 0
|
||
# 解析类名(AnnotClassName;去模块前缀)
|
||
class_nm_v: str = None
|
||
if at.value.kind() == ast.ASTKind.Name:
|
||
nm_v: ast.Name* = ast.Name*(at.value)
|
||
if nm_v.id is not None:
|
||
ve_v: GenTypes.VarEntry* = self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm_v.id)
|
||
if ve_v is not None:
|
||
class_nm_v = self.Gen.VarGen.var_annot_class_name(ve_v)
|
||
elif at.value.kind() == ast.ASTKind.Attribute:
|
||
# 跨 Mixin:_resolve_attr_field_class 定义在 ExprGenAttr,经 self.Gen 调用
|
||
class_nm_v = self.Gen.ExprGenAttr._resolve_attr_field_class(pool, trans, at.value)
|
||
if class_nm_v is None: return 0
|
||
fd_dot_v: str = string.strrchr(class_nm_v, '.')
|
||
if fd_dot_v is not None:
|
||
class_nm_v = fd_dot_v + 1
|
||
if self.Gen.StructGen.get_struct_type(class_nm_v) is None: return 0
|
||
vm_idx_v: int = self.Gen.StructGen.get_vtable_method_index(class_nm_v, at.attr)
|
||
if vm_idx_v < 0: return 0
|
||
# 解析 obj_ptr(对齐 get_attribute_ptr 前半段:Name 直接查 alloca)
|
||
obj_ptr_v: llvmlite.Value* = None
|
||
if at.value.kind() == ast.ASTKind.Name:
|
||
obj_ptr_v = self.Gen.VarGen.lookup_var(trans.SymTab, (ast.Name*(at.value)).id)
|
||
else:
|
||
obj_ptr_v = self.Gen.ExprGen.translate_value(builder, pool, mod, at.value, None, 0, trans)
|
||
if obj_ptr_v is None or obj_ptr_v.Ty is None: return 0
|
||
# X|t.CPtr 变量(Ptr(Ptr))load 解引用取对象指针
|
||
match obj_ptr_v.Ty:
|
||
case llvmlite.LLVMType.Ptr(inner_v):
|
||
match inner_v:
|
||
case llvmlite.LLVMType.Ptr(_):
|
||
obj_ptr_v = llvmlite.build_load(builder, inner_v, obj_ptr_v)
|
||
case _:
|
||
pass
|
||
case _:
|
||
pass
|
||
if obj_ptr_v is None:
|
||
return 0
|
||
return self._write_vtable_slot(pool, builder, mod, obj_ptr_v, class_nm_v, vm_idx_v, rhs_val, trans) |