- 删 FuncEntry.TypeStr 字段、_build_func_type_str 生产者、_check_func_spec_text 闸门 - update_global_func_typestr 改名 update_global_func_spec,仅填 Spec(去 pool 参数) - ClassGenVTable vtable 合并 func_valid 分支,统一 SpecToLLVMText 派生 - 同步 FuncGenDef/ClassGenVTable/GenApi/VpiReader 调用点
1463 lines
74 KiB
Plaintext
1463 lines
74 KiB
Plaintext
import lib.core.Gen.GenTypes as GenTypes
|
||
import t, c
|
||
from stdint import *
|
||
import ast
|
||
import llvmlite
|
||
import memhub
|
||
import string
|
||
import stdlib
|
||
import viperlib
|
||
import lib.core.VLogger as VLogger
|
||
import lib.core.Gen.GenApi as GenApi
|
||
import lib.core.Gen.Translator as HT
|
||
import lib.core.CompilerFactory as CompilerFactory
|
||
import lib.core.Gen.Type.TypeSpec as TSpec
|
||
|
||
from . import CallGenCBuiltin
|
||
|
||
|
||
# ============================================================
|
||
# CallGenLeafKit - CallGenMixin 拆分 3/9:EH/isinstance/闭包/print/函数表
|
||
#
|
||
# 按功能域从 CallGenMixin.vp 拆出(500~1500 行/文件架构重构):
|
||
# EH 防护 + isinstance + 闭包/函数指针 + printf/print + 全局函数表/默认参数表。
|
||
# 继承 CallGenCBuiltin。
|
||
#
|
||
# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。
|
||
# ============================================================
|
||
|
||
|
||
# ============================================================
|
||
# 常量(与 HandlesExprCall 保持一致,本地副本避免跨模块 CDefine 查找 bug)
|
||
# ============================================================
|
||
GLOBAL_FUNC_MAX: t.CDefine = 8192
|
||
GLOBAL_DEFAULTS_MAX: t.CDefine = 4096
|
||
_CEXPORT_MAX: t.CDefine = 256
|
||
ASM_MAX_OPERANDS: t.CDefine = 16
|
||
ASM_TEXT_BUF_SIZE: t.CDefine = 2048
|
||
ASM_CONST_BUF_SIZE: t.CDefine = 512
|
||
ASM_ARGS_BUF_SIZE: t.CDefine = 512
|
||
ASM_LINE_BUF_SIZE: t.CDefine = 4096
|
||
LLVMIR_MAX_OPS: t.CDefine = 16
|
||
LLVMIR_TEMPLATE_BUF: t.CDefine = 512
|
||
# 闭包名表大小(原 HandlesExprCall 模块级常量)
|
||
MAX_CLOSURE_NAMES: t.CDefine = 128
|
||
# 函数指针签名表大小(原 HandlesExprCall 模块级常量)
|
||
MAX_FUNC_PTR_SIGS: t.CDefine = 64
|
||
# isinstance 子类收集上限(防数组越界;t.CDefine 注解由 TPC 解析为 i32)
|
||
ISINSTANCE_CLASS_MAX: t.CDefine = 64
|
||
|
||
|
||
# ============================================================
|
||
# CallGenLeafKit - EH/isinstance/闭包/print/函数表
|
||
# ============================================================
|
||
@t.NoVTable
|
||
class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
|
||
"""EH 防护 + isinstance + 闭包 + print + 全局函数表(继承 CBuiltin)"""
|
||
|
||
|
||
# ============================================================
|
||
# _func_has_eh_params - 被调函数签名是否含 try-except EH 输出参数
|
||
#
|
||
# EH 参数(%__eh_msg_out__/__eh_code_out__)由 translate_function_def/
|
||
# _translate_method 在含 raise 的函数签名末尾注入(main 除外)。
|
||
# ============================================================
|
||
def _func_has_eh_params(self, func: llvmlite.Function | t.CPtr) -> int:
|
||
"""返回 1=函数带 EH 输出参数 / 0=不带"""
|
||
if func is None:
|
||
return 0
|
||
cur_p: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(func)
|
||
while cur_p is not None:
|
||
pn: str = llvmlite.param_get_name(cur_p)
|
||
if pn is not None and string.strcmp(pn, "%__eh_msg_out__") == 0:
|
||
return 1
|
||
cur_p = llvmlite.param_get_next(cur_p)
|
||
return 0
|
||
|
||
# ============================================================
|
||
# _emit_eh_guarded_call - 调用侧 try-except EH 检测(对齐 TPC
|
||
# HandlesExprCall._append_eh_msg_out_arg + _check_eh_return)
|
||
#
|
||
# 被调函数带 EH 输出参数时:
|
||
# 1. 确定 msg/code 输出指针:
|
||
# - 当前在 try(trans._eh_dispatch_bb 非空):复用 try 的
|
||
# eh_message/exception_code alloca——被调函数直接写入,检查
|
||
# 路径读同一 alloca 即得异常,无需搬运
|
||
# - 当前函数有 EH 输出参数:复用本函数 out 参数(异常直接写进
|
||
# 本函数输出,检查命中后仅返回,由调用方接管传播)
|
||
# - 两者皆无:局部 null alloca(异常被吞)
|
||
# 2. 调用前清零输出指针(复用 alloca 必须复位,防上次残留误判)
|
||
# 3. 追加 msg/code 两个实参(count+2)
|
||
# 4. 调用后检查 msg != null:命中 → err 块(try 内分支 DispatchBB;
|
||
# 否则仅返回默认值);未命中 → ok 块继续
|
||
# ============================================================
|
||
|
||
# ============================================================
|
||
def _emit_eh_guarded_call(self, builder: llvmlite.IRBuilder | t.CPtr,
|
||
pool: memhub.MemBuddy | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
trans: HT.Translator | t.CPtr,
|
||
func: llvmlite.Function | t.CPtr,
|
||
call_name: str,
|
||
head: llvmlite.Value | t.CPtr,
|
||
count: int,
|
||
ret_ty: llvmlite.LLVMType | t.CPtr,
|
||
is_variadic: int) -> llvmlite.Value | t.CPtr:
|
||
"""带 try-except EH 检测的函数调用,返回 call 结果(检查后位于 ok 块)"""
|
||
if trans is None or self._func_has_eh_params(func) == 0:
|
||
return llvmlite.build_call(builder, call_name, head, count, ret_ty, is_variadic)
|
||
# ---- 1. 确定输出指针 ----
|
||
i8_ty_g: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||
i8_ptr_ty_g: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_g)
|
||
i32_ty_g: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||
if i8_ty_g is None or i8_ptr_ty_g is None or i32_ty_g is None:
|
||
return llvmlite.build_call(builder, call_name, head, count, ret_ty, is_variadic)
|
||
msg_ptr: llvmlite.Value | t.CPtr = None
|
||
code_ptr: llvmlite.Value | t.CPtr = None
|
||
if trans._eh_msg_ptr is not None and trans._eh_code_ptr is not None:
|
||
msg_ptr = trans._eh_msg_ptr
|
||
code_ptr = trans._eh_code_ptr
|
||
elif trans._cur_func_has_eh != 0 and trans._eh_msg_out_param is not None \
|
||
and trans._eh_code_out_param is not None:
|
||
msg_ptr = trans._eh_msg_out_param
|
||
code_ptr = trans._eh_code_out_param
|
||
if msg_ptr is None:
|
||
msg_ptr = self.Gen.VarGen._alloca_at_entry(builder, i8_ptr_ty_g)
|
||
code_ptr = self.Gen.VarGen._alloca_at_entry(builder, i32_ty_g)
|
||
# ---- 2. 调用前清零 ----
|
||
null_msg_g: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, i8_ptr_ty_g, "null")
|
||
zero_code_g: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0)
|
||
if null_msg_g is not None:
|
||
llvmlite.build_store(builder, null_msg_g, msg_ptr)
|
||
if zero_code_g is not None:
|
||
llvmlite.build_store(builder, zero_code_g, code_ptr)
|
||
# ---- 3. 追加实参(链表末尾 + count+2)----
|
||
msg_ptr.Next = code_ptr
|
||
code_ptr.Next = None
|
||
if head is None:
|
||
head = msg_ptr
|
||
else:
|
||
tail_g: llvmlite.Value | t.CPtr = head
|
||
while tail_g.Next is not None:
|
||
tail_g = tail_g.Next
|
||
tail_g.Next = msg_ptr
|
||
count = count + 2
|
||
# ---- 4. 调用 + 检查 ----
|
||
result: llvmlite.Value | t.CPtr = llvmlite.build_call(
|
||
builder, call_name, head, count, ret_ty, is_variadic)
|
||
cur_func_g: llvmlite.Function | t.CPtr = trans._cur_func
|
||
if cur_func_g is None or null_msg_g is None:
|
||
return result
|
||
msg_val_g: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||
builder, i8_ptr_ty_g, msg_ptr)
|
||
if msg_val_g is None:
|
||
return result
|
||
is_err_g: llvmlite.Value | t.CPtr = llvmlite.build_icmp(
|
||
builder, llvmlite.ICMP_NE, msg_val_g, null_msg_g)
|
||
if is_err_g is None:
|
||
return result
|
||
lc_g: int = trans._label_counter
|
||
trans._label_counter = lc_g + 1
|
||
bb_buf_g: str = pool.alloc(64)
|
||
if bb_buf_g is None:
|
||
return result
|
||
viperlib.snprintf(bb_buf_g, 64, "eh.err.%d", lc_g)
|
||
err_bb_g: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
|
||
pool, cur_func_g, bb_buf_g)
|
||
viperlib.snprintf(bb_buf_g, 64, "eh.ok.%d", lc_g)
|
||
ok_bb_g: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
|
||
pool, cur_func_g, bb_buf_g)
|
||
if err_bb_g is None or ok_bb_g is None:
|
||
return result
|
||
llvmlite.build_cond_br(builder, is_err_g, err_bb_g, ok_bb_g)
|
||
# err 块
|
||
llvmlite.position_at_end(builder, err_bb_g)
|
||
if trans._eh_dispatch_bb is not None:
|
||
# try 内:异常已写入 try 的 alloca(code_ptr 即 try 的 alloca),
|
||
# 分支 DispatchBB 交给 except 链
|
||
llvmlite.build_br(builder, trans._eh_dispatch_bb)
|
||
else:
|
||
# 非 try:异常已写入本函数 out 参数(复用)或局部 alloca(吞掉),
|
||
# 仅返回默认值,由调用方检测本函数 out 参数
|
||
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
|
||
ret_ty_g2: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(
|
||
cur_func_g)
|
||
if ret_ty_g2 is not None:
|
||
match ret_ty_g2:
|
||
case llvmlite.LLVMType.Void():
|
||
llvmlite.build_ret_void(builder)
|
||
case llvmlite.LLVMType.Ptr(_pg):
|
||
nv_g: llvmlite.Value | t.CPtr = llvmlite.ConstNull(
|
||
pool, ret_ty_g2, "null")
|
||
if nv_g is not None:
|
||
llvmlite.build_ret(builder, nv_g)
|
||
case llvmlite.LLVMType.Float(_fg):
|
||
zf_g: llvmlite.Value | t.CPtr = llvmlite.ConstFloat(
|
||
pool, ret_ty_g2, 0.0)
|
||
if zf_g is not None:
|
||
llvmlite.build_ret(builder, zf_g)
|
||
case _:
|
||
zv_g: llvmlite.Value | t.CPtr = llvmlite.ConstZero(
|
||
pool, ret_ty_g2)
|
||
if zv_g is not None:
|
||
llvmlite.build_ret(builder, zv_g)
|
||
# ok 块:继续
|
||
llvmlite.position_at_end(builder, ok_bb_g)
|
||
return result
|
||
|
||
# ============================================================
|
||
# isinstance - 运行时 vtable 子类集合比较(2026-08-10)
|
||
#
|
||
# CVTable 对象头部 vtable 指针唯一标识对象实际类。isinstance(obj, Cls)
|
||
# 语义 = Cls 是实际类的祖先(实际类 == Cls 或继承自 Cls)。运行时只能
|
||
# 拿到实际类 vtable 地址,无法向上推导祖先链,因此在编译期沿
|
||
# StructEntry.ParentNames 反向 BFS 枚举 Cls 的全部已知子类(含自身),
|
||
# 运行时比较 obj->vtable ∈ {Cls 子类 vtable 地址集合}。
|
||
# NoVTable / 未知类回退编译时静态判断(obj 静态类型 MRO 判断)。
|
||
# ============================================================
|
||
|
||
|
||
|
||
def _translate_isinstance(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
obj_node: ast.AST | t.CPtr,
|
||
cls_node: ast.AST | t.CPtr,
|
||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||
"""isinstance(obj, Cls):运行时 vtable 子类集合比较,返回 i1"""
|
||
if obj_node is None or cls_node is None:
|
||
# 参数缺失即调用错误:fail-fast,绝不返回 True 掩盖
|
||
self.Gen.TypeGenErr.fatal_error(cls_node, "isinstance() 参数类型推断失败", "TypeError")
|
||
obj_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, obj_node, None, 0, trans)
|
||
if obj_val is None or obj_val.Ty is None:
|
||
# obj 类型推断失败:fail-fast,绝不返回 True 掩盖
|
||
self.Gen.TypeGenErr.fatal_error(cls_node, "isinstance() 参数类型推断失败", "TypeError")
|
||
# 对象指针规整:二级指针(变量 alloca / 联合 Class|t.CPtr)先 load
|
||
obj_ptr: llvmlite.Value | t.CPtr = obj_val
|
||
match obj_val.Ty:
|
||
case llvmlite.LLVMType.Ptr(inner_ty):
|
||
match inner_ty:
|
||
case llvmlite.LLVMType.Ptr(_):
|
||
loaded: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||
builder, inner_ty, obj_val)
|
||
if loaded is not None:
|
||
obj_ptr = loaded
|
||
case _:
|
||
pass
|
||
obj_is_ptr: int = self.Gen.ExprGenBase.is_ptr_type(obj_ptr.Ty)
|
||
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
|
||
i8_ptr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty)
|
||
# 对象 vtable 指针惰性读取(首个 CVTable 类比较时执行一次)
|
||
vtable_ptr: llvmlite.Value | t.CPtr = None
|
||
vtable_ready: int = 0
|
||
res: llvmlite.Value | t.CPtr = None
|
||
cls_names: sizet | t.CPtr = self._extract_isinstance_class_names(pool, cls_node)
|
||
if cls_names is None:
|
||
# 类名提取失败:fail-fast,绝不返回 True 掩盖
|
||
self.Gen.TypeGenErr.fatal_error(cls_node, "isinstance() 参数类型推断失败", "TypeError")
|
||
ci: int = 0
|
||
while cls_names[ci] != 0:
|
||
cn: str = (str | t.CPtr)(t.CVoid(cls_names[ci], t.CPtr))
|
||
if cn is not None:
|
||
if self.Gen.StructGen.is_novtable_by_name(cn) != 0 \
|
||
or self.Gen.StructGen.has_vtable_by_name(cn) == 0:
|
||
# NoVTable / 未知类 → 编译时静态判断(obj 静态类型 MRO)
|
||
st: int = self._isinstance_compile_time(pool, obj_ptr, cn)
|
||
c1: llvmlite.Value | t.CPtr = llvmlite.const_int(pool, 1, 1 if st > 0 else 0)
|
||
if res is None:
|
||
res = c1
|
||
else:
|
||
res = llvmlite.build_or(builder, res, c1)
|
||
elif obj_is_ptr != 0:
|
||
# CVTable → 运行时 vtable 比较(读对象头部 vtable 指针)
|
||
if vtable_ready == 0:
|
||
vtable_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
|
||
builder, obj_ptr, i8_ptr_ptr_ty)
|
||
if vtable_slot is not None:
|
||
vtable_ptr = llvmlite.build_load(builder, i8_ptr_ty, vtable_slot)
|
||
vtable_ready = 1
|
||
if vtable_ptr is not None:
|
||
subs: sizet | t.CPtr = self._collect_subclass_vtable_classes(pool, cn)
|
||
if subs is not None:
|
||
k: int = 0
|
||
while subs[k] != 0:
|
||
scn: str = (str | t.CPtr)(t.CVoid(subs[k], t.CPtr))
|
||
if scn is not None:
|
||
sub_i8: llvmlite.Value | t.CPtr = self._make_vtable_ref_i8(
|
||
pool, builder, mod, scn, trans)
|
||
if sub_i8 is not None:
|
||
cmp: llvmlite.Value | t.CPtr = llvmlite.build_icmp(
|
||
builder, llvmlite.ICMP_EQ, vtable_ptr, sub_i8)
|
||
if cmp is not None:
|
||
if res is None:
|
||
res = cmp
|
||
else:
|
||
res = llvmlite.build_or(builder, res, cmp)
|
||
k += 1
|
||
ci += 1
|
||
if res is None:
|
||
# 未产生任何比较结果(obj 非指针且类全部为 CVTable):推断失败,fail-fast
|
||
self.Gen.TypeGenErr.fatal_error(cls_node, "isinstance() 参数类型推断失败", "TypeError")
|
||
return res
|
||
|
||
|
||
def _extract_isinstance_class_names(self, pool: memhub.MemBuddy | t.CPtr,
|
||
node: ast.AST | t.CPtr) -> sizet | t.CPtr:
|
||
"""从 isinstance 第二参数提取类名数组(Name→id / Attribute→attr / Tuple→遍历)"""
|
||
arr: sizet | t.CPtr = pool.alloc(8 * 16)
|
||
if arr is None:
|
||
return None
|
||
# 全数组清零:pool 分配内存非零时,未初始化槽位会被 while cls_names[ci]!=0
|
||
# 误当类名指针解引用 → 段错误
|
||
string.memset(arr, 0, 8 * 16)
|
||
arr[0] = 0
|
||
if node is None:
|
||
return arr
|
||
count: int = 0
|
||
k: int = node.kind()
|
||
if k == ast.ASTKind.Name:
|
||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node)
|
||
if nm.id is not None:
|
||
arr[0] = sizet(nm.id)
|
||
elif k == ast.ASTKind.Attribute:
|
||
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node)
|
||
if at.attr is not None:
|
||
arr[0] = sizet(at.attr)
|
||
elif k == ast.ASTKind.Tuple:
|
||
tp: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(node)
|
||
elts: list[ast.AST | t.CPtr] | t.CPtr = tp.elts
|
||
if elts is not None:
|
||
n: sizet = len(elts)
|
||
for i in range(n):
|
||
if count >= 15:
|
||
break
|
||
elt: ast.AST | t.CPtr = elts.get(i)
|
||
if elt is None:
|
||
continue
|
||
ek: int = elt.kind()
|
||
if ek == ast.ASTKind.Name:
|
||
enm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(elt)
|
||
if enm.id is not None:
|
||
arr[count] = sizet(enm.id)
|
||
count += 1
|
||
elif ek == ast.ASTKind.Attribute:
|
||
eat: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(elt)
|
||
if eat.attr is not None:
|
||
arr[count] = sizet(eat.attr)
|
||
count += 1
|
||
arr[count] = 0
|
||
return arr
|
||
|
||
|
||
def _collect_subclass_vtable_classes(self, pool: memhub.MemBuddy | t.CPtr,
|
||
class_name: str) -> sizet | t.CPtr:
|
||
"""反向 BFS 收集目标类及全部子类(含自身,仅 HasVTable==1),返回 0 结尾数组"""
|
||
if class_name is None:
|
||
return None
|
||
names: sizet | t.CPtr = pool.alloc(8 * (ISINSTANCE_CLASS_MAX + 1))
|
||
queue: sizet | t.CPtr = pool.alloc(8 * ISINSTANCE_CLASS_MAX)
|
||
visited: sizet | t.CPtr = pool.alloc(8 * ISINSTANCE_CLASS_MAX)
|
||
if names is None or queue is None or visited is None:
|
||
return None
|
||
string.memset(names, 0, 8 * (ISINSTANCE_CLASS_MAX + 1))
|
||
string.memset(queue, 0, 8 * ISINSTANCE_CLASS_MAX)
|
||
string.memset(visited, 0, 8 * ISINSTANCE_CLASS_MAX)
|
||
qcount: int = 1
|
||
outcount: int = 0
|
||
vcount: int = 0
|
||
queue[0] = sizet(class_name) # 存疑
|
||
while qcount > 0:
|
||
qcount -= 1
|
||
cur_addr: sizet = queue[qcount]
|
||
cur: str = (str | t.CPtr)(t.CVoid(cur_addr, t.CPtr))
|
||
if cur is None:
|
||
continue
|
||
dup: int = 0
|
||
for vi in range(vcount):
|
||
va: sizet = visited[vi]
|
||
if va != 0:
|
||
vn: str = (str | t.CPtr)(t.CVoid(va, t.CPtr))
|
||
if vn is not None and string.strcmp(vn, cur) == 0:
|
||
dup = 1
|
||
break
|
||
if dup != 0:
|
||
continue
|
||
if vcount < ISINSTANCE_CLASS_MAX:
|
||
visited[vcount] = sizet(cur)
|
||
vcount += 1
|
||
centry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct(cur)
|
||
if centry is not None and centry.HasVTable != 0:
|
||
if outcount < ISINSTANCE_CLASS_MAX:
|
||
names[outcount] = sizet(cur)
|
||
outcount += 1
|
||
# 子类入队:遍历全部已注册 struct,ParentNames 含 cur 者
|
||
scnt: int = self.Gen.StructGen.get_struct_count()
|
||
for i in range(scnt):
|
||
e2: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen._get_struct_entry(i)
|
||
if e2 is None or e2.Name is None:
|
||
continue
|
||
if e2.ParentCount > 0 and e2.ParentNames is not None:
|
||
parr: sizet | t.CPtr = (sizet | t.CPtr)(t.CVoid(e2.ParentNames, t.CPtr))
|
||
for j in range(e2.ParentCount):
|
||
pa: sizet = parr[j]
|
||
if pa != 0:
|
||
pn: str = (str | t.CPtr)(t.CVoid(pa, t.CPtr))
|
||
if pn is not None and string.strcmp(pn, cur) == 0:
|
||
if qcount < ISINSTANCE_CLASS_MAX:
|
||
queue[qcount] = sizet(e2.Name)
|
||
qcount += 1
|
||
break
|
||
names[outcount] = 0
|
||
return names
|
||
|
||
|
||
def _make_vtable_ref_i8(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
class_name: str,
|
||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||
"""构造类 vtable 地址引用(i8*):本模块已定义直接引用,跨模块声明 external"""
|
||
if class_name is None:
|
||
return None
|
||
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
|
||
buf: str = pool.alloc(256)
|
||
if buf is None:
|
||
return None
|
||
viperlib.snprintf(buf, 256, "%s.vtable", class_name)
|
||
vn: str = (str | t.CPtr)(buf)
|
||
sha1: str = self.Gen.StructGen.get_struct_sha1(class_name)
|
||
if sha1 is None:
|
||
if trans is None:
|
||
return None
|
||
sha1 = trans.ModuleSha1
|
||
if sha1 is None:
|
||
return None
|
||
mangled: str = self.Gen.FuncGenBase._mangle_name_with_sha1(sha1, vn)
|
||
ref_name: str = pool.alloc(256)
|
||
if ref_name is None:
|
||
return None
|
||
# vtable 名含 sha1 点号前缀,一律 @"..." 引号形式
|
||
viperlib.snprintf(ref_name, 256, "@\"%s\"", mangled)
|
||
gv: llvmlite.GlobalVariable | t.CPtr = self.Gen.ExprGenAttr.find_global_in_module(mod, mangled)
|
||
ref_ty: llvmlite.LLVMType | t.CPtr = None
|
||
if gv is not None:
|
||
# 本模块已定义 vtable(constant {i8* x N})→ 引用类型 Ptr(struct)
|
||
ref_ty = llvmlite.Ptr(pool, gv.Ty)
|
||
else:
|
||
# 跨模块:声明 @mangled = external global i8*,引用类型 i8**
|
||
gv2: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(
|
||
pool, mangled, i8_ptr_ty)
|
||
if gv2 is None:
|
||
return None
|
||
llvmlite.module_add_global(mod, gv2)
|
||
ref_ty = llvmlite.Ptr(pool, i8_ptr_ty)
|
||
ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, ref_ty, ref_name)
|
||
if ref is None:
|
||
return None
|
||
return llvmlite.build_bitcast(builder, ref, i8_ptr_ty)
|
||
|
||
|
||
def _isinstance_compile_time(self, pool: memhub.MemBuddy | t.CPtr,
|
||
obj_ptr: llvmlite.Value | t.CPtr,
|
||
class_name: str) -> int:
|
||
"""编译时静态判断:obj 静态类型 == class_name 或 class_name 在其 MRO 中"""
|
||
if obj_ptr is None or obj_ptr.Ty is None or class_name is None:
|
||
return 0
|
||
match obj_ptr.Ty:
|
||
case llvmlite.LLVMType.Ptr(obj_struct_ty):
|
||
sname: str = self.Gen.StructGen.get_class_name_by_type(pool, obj_struct_ty)
|
||
if sname is not None:
|
||
if string.strcmp(sname, class_name) == 0:
|
||
return 1
|
||
mro: sizet | t.CPtr = self.Gen.StructGen.get_mro_chain(pool, sname)
|
||
if mro is not None:
|
||
k: int = 0
|
||
while mro[k] != 0:
|
||
mn: str = (str | t.CPtr)(t.CVoid(mro[k], t.CPtr))
|
||
if mn is not None and string.strcmp(mn, class_name) == 0:
|
||
return 1
|
||
k += 1
|
||
case _:
|
||
pass
|
||
return 0
|
||
|
||
# ============================================================
|
||
# P4 簇 5+6 迁移方法(函数体来自 HandlesExprCall.vp:
|
||
# 闭包调用/函数指针/printf/print/stdarg 糖/变长参数提升/函数表/全局注册表)
|
||
# 本模块函数调用改 self.,外部模块调用保留模块前缀,全局变量改 self 字段
|
||
# ============================================================
|
||
|
||
|
||
|
||
def translate_closure_call(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
closure_alloca: llvmlite.Value | t.CPtr,
|
||
cargs: list[ast.AST | t.CPtr] | t.CPtr,
|
||
can: sizet,
|
||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||
"""通过闭包指针间接调用(支持带参 lambda:i32(i8*, args...))"""
|
||
if builder is None or closure_alloca is None:
|
||
return None
|
||
|
||
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
|
||
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||
|
||
# 1. 加载闭包指针 (i8*)
|
||
closure_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, closure_alloca)
|
||
if closure_ptr is None:
|
||
return None
|
||
|
||
# 2. 加载 fn_ptr (offset 0): bitcast to i8**, load i8*
|
||
fn_ptr_addr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, closure_ptr, llvmlite.Ptr(pool, i8_ptr_ty))
|
||
if fn_ptr_addr is None:
|
||
return None
|
||
fn_raw: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, fn_ptr_addr)
|
||
if fn_raw is None:
|
||
return None
|
||
|
||
# 3. 加载 env_ptr (offset 8): GEP i8, closure, 8; load i8*
|
||
eight_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 8)
|
||
env_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, closure_ptr, eight_val)
|
||
if env_addr is None:
|
||
return None
|
||
env_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, env_addr)
|
||
if env_ptr is None:
|
||
return None
|
||
|
||
# 4. 构建参数:env 头 + 实参尾(带参 lambda 时翻译实参)
|
||
total_args: int = 1
|
||
arg_head: llvmlite.Value | t.CPtr = env_ptr
|
||
arg_tail: llvmlite.Value | t.CPtr = env_ptr
|
||
param_node: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, i8_ptr_ty)
|
||
pn_tail: llvmlite.ParamNode | t.CPtr = param_node
|
||
if can > 0 and cargs is not None and trans is not None:
|
||
for ai in range(can):
|
||
arg: ast.AST | t.CPtr = cargs.get(ai)
|
||
if arg is None:
|
||
continue
|
||
arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, arg, None, 0, trans)
|
||
if arg_val is None or arg_val.Ty is None:
|
||
continue
|
||
arg_val.Next = None
|
||
if arg_tail is not None:
|
||
arg_tail.Next = arg_val
|
||
arg_tail = arg_val
|
||
pn_new: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, arg_val.Ty)
|
||
if pn_new is not None:
|
||
pn_tail.Next = pn_new
|
||
pn_tail = pn_new
|
||
total_args += 1
|
||
if total_args == 1:
|
||
env_ptr.Next = None
|
||
|
||
# 5. bitcast fn_raw 到函数指针类型 i32(i8*, [args...])*
|
||
func_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func(pool, i32_ty, param_node, total_args)
|
||
func_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, func_ty)
|
||
fn_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, fn_raw, func_ptr_ty)
|
||
if fn_typed is None:
|
||
return None
|
||
|
||
# 6. 间接调用: call i32 %fn_typed(env, args...)
|
||
return llvmlite.build_call_indirect(builder, fn_typed, arg_head, total_args, i32_ty)
|
||
|
||
|
||
def _is_func_ptr_alloca(self, alloca: llvmlite.Value | t.CPtr) -> int:
|
||
"""判断 alloca 是否为函数指针变量(类型 Ptr(Ptr(i8))),1=是 / 0=否"""
|
||
if alloca is None or alloca.Ty is None:
|
||
return 0
|
||
if self.Gen.ExprGenBase.is_ptr_type(alloca.Ty) == 0:
|
||
return 0
|
||
pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee
|
||
if pointee is None or self.Gen.ExprGenBase.is_ptr_type(pointee) == 0:
|
||
return 0
|
||
inner: llvmlite.LLVMType | t.CPtr = pointee.Pointee
|
||
if inner is None or self.Gen.ExprGenBase.is_ptr_type(inner) != 0:
|
||
return 0
|
||
return 1
|
||
|
||
|
||
def _ensure_closure_names(self) -> int:
|
||
"""确保闭包名表已分配,0 失败"""
|
||
if self.ClosureNames is not None:
|
||
return 1
|
||
self.ClosureNames = CompilerFactory.factory.PermPool.alloc(64 * MAX_CLOSURE_NAMES)
|
||
if self.ClosureNames is None:
|
||
return 0
|
||
string.memset(self.ClosureNames, 0, 64 * MAX_CLOSURE_NAMES)
|
||
return 1
|
||
|
||
|
||
def register_closure_name(self, name: str) -> int:
|
||
"""注册嵌套函数(闭包变量)名,0 成功"""
|
||
if name is None:
|
||
return 1
|
||
if self._ensure_closure_names() == 0:
|
||
return 1
|
||
if self.ClosureCount >= MAX_CLOSURE_NAMES:
|
||
return 1
|
||
idx: sizet = sizet(self.ClosureCount) * 64
|
||
string.strncpy(self.ClosureNames + idx, name, 63)
|
||
self.ClosureCount += 1
|
||
return 0
|
||
|
||
|
||
def is_closure_name(self, name: str) -> int:
|
||
"""检查 name 是否已注册为闭包变量名,1=是 / 0=否"""
|
||
if name is None or self.ClosureNames is None:
|
||
return 0
|
||
i: sizet
|
||
for i in range(self.ClosureCount):
|
||
if string.strcmp(self.ClosureNames + i * 64, name) == 0:
|
||
return 1
|
||
return 0
|
||
|
||
|
||
def _ensure_funcptr_sigs(self) -> int:
|
||
"""确保函数指针签名表已分配(stdlib.malloc,懒初始化)"""
|
||
if self.FuncptrNames is not None:
|
||
return 1
|
||
self.FuncptrNames = CompilerFactory.factory.PermPool.alloc(64 * MAX_FUNC_PTR_SIGS)
|
||
self.FuncptrRets = CompilerFactory.factory.PermPool.alloc(8 * MAX_FUNC_PTR_SIGS)
|
||
if self.FuncptrNames is None or self.FuncptrRets is None:
|
||
return 0
|
||
string.memset(self.FuncptrNames, 0, 64 * MAX_FUNC_PTR_SIGS)
|
||
return 1
|
||
|
||
|
||
def register_func_ptr_sig(self, name: str,
|
||
ret_ty: llvmlite.LLVMType | t.CPtr) -> int:
|
||
"""注册函数指针变量的返回类型签名,0 成功"""
|
||
if name is None or ret_ty is None:
|
||
return 1
|
||
if self._ensure_funcptr_sigs() == 0:
|
||
return 1
|
||
if self.FuncptrCount >= MAX_FUNC_PTR_SIGS:
|
||
return 1
|
||
idx: sizet = sizet(self.FuncptrCount) * 64
|
||
# 槽位定长 64 字节,与 register_closure_name 一致用 strncpy 钳制防越界
|
||
string.strncpy(self.FuncptrNames + idx, name, 63)
|
||
# ret_ty 是调用方 pool 分配的裸 LLVMType,1a 每文件 reset 后悬空;
|
||
# 深拷贝到 perm_pool(lookup_func_ptr_ret 跨文件读取)
|
||
ret_copy_fp: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType(
|
||
CompilerFactory.factory.PermPool, ret_ty)
|
||
if ret_copy_fp is not None:
|
||
self.FuncptrRets[self.FuncptrCount] = uint64(ret_copy_fp)
|
||
else:
|
||
self.FuncptrRets[self.FuncptrCount] = uint64(ret_ty)
|
||
self.FuncptrCount += 1
|
||
return 0
|
||
|
||
|
||
def lookup_func_ptr_ret(self, name: str) -> llvmlite.LLVMType | t.CPtr:
|
||
"""查函数指针变量的返回类型,None=未注册(调用时默认 i32)"""
|
||
if name is None or self.FuncptrNames is None:
|
||
return None
|
||
for i in range(self.FuncptrCount):
|
||
idx: sizet = sizet(i) * 64
|
||
if string.strcmp(self.FuncptrNames + idx, name) == 0:
|
||
return (llvmlite.LLVMType | t.CPtr)(
|
||
t.CVoid(self.FuncptrRets[i], t.CPtr))
|
||
return None
|
||
|
||
|
||
def _translate_func_ptr_call(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
fp_alloca: llvmlite.Value | t.CPtr,
|
||
func_name: str,
|
||
cargs: list[ast.AST | t.CPtr] | t.CPtr,
|
||
can: sizet,
|
||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||
"""函数指针变量间接调用,返回结果 Value"""
|
||
if builder is None or fp_alloca is None:
|
||
return None
|
||
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
|
||
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||
|
||
# 1. load 函数地址 (i8*)
|
||
fn_i8: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, fp_alloca)
|
||
if fn_i8 is None:
|
||
return None
|
||
|
||
# 2. 翻译实参并链接为 Value 链表
|
||
head: llvmlite.Value | t.CPtr = None
|
||
tail: llvmlite.Value | t.CPtr = None
|
||
arg_count: int = 0
|
||
ai: sizet
|
||
for ai in range(can):
|
||
arg: ast.AST | t.CPtr = cargs.get(ai)
|
||
if arg is not None:
|
||
arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, arg, None, 0, trans)
|
||
if arg_val is not None:
|
||
arg_val.Next = None
|
||
if head is None:
|
||
head = arg_val
|
||
else:
|
||
tail.Next = arg_val
|
||
tail = arg_val
|
||
arg_count += 1
|
||
|
||
# 3. 按实参类型 + 注册的返回类型构造签名(未注册即 t.Callable 注解缺失,fail-fast)
|
||
ret_ty: llvmlite.LLVMType | t.CPtr = self.lookup_func_ptr_ret(func_name)
|
||
if ret_ty is None:
|
||
self.Gen.TypeGenErr.fatal_error(
|
||
None,
|
||
f"函数指针变量 '{func_name}' 的返回类型未注册(t.Callable 注解缺失)",
|
||
"TypeError")
|
||
ret_ty = i32_ty
|
||
fp_first: llvmlite.ParamNode | t.CPtr = None
|
||
fp_prev: llvmlite.ParamNode | t.CPtr = None
|
||
cur_v: llvmlite.Value | t.CPtr = head
|
||
for pi in range(arg_count):
|
||
if cur_v is None:
|
||
break
|
||
cur_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(cur_v)
|
||
pn2: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, cur_ty)
|
||
if pn2 is not None:
|
||
if fp_first is None:
|
||
fp_first = pn2
|
||
if fp_prev is not None:
|
||
llvmlite.paramnode_set_next(fp_prev, pn2)
|
||
fp_prev = pn2
|
||
cur_v = llvmlite.value_get_next(cur_v)
|
||
|
||
func_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func(pool, ret_ty, fp_first, arg_count)
|
||
if func_ty is None:
|
||
return None
|
||
func_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, func_ty)
|
||
|
||
# 4. bitcast i8* → 函数指针类型,间接调用
|
||
fn_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, fn_i8, func_ptr_ty)
|
||
if fn_typed is None:
|
||
return None
|
||
return llvmlite.build_call_indirect(builder, fn_typed, head, arg_count, ret_ty)
|
||
|
||
|
||
def translate_printf_call(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
cl: ast.Call | t.CPtr,
|
||
trans: HT.Translator | t.CPtr = None) -> None:
|
||
"""翻译 printf 调用(特殊处理格式字符串)"""
|
||
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
|
||
if cargs is None:
|
||
return
|
||
can: sizet = len(cargs)
|
||
if can == 0:
|
||
return
|
||
|
||
arg0: ast.AST | t.CPtr = cargs.get(0)
|
||
if arg0 is None:
|
||
return
|
||
|
||
fmt_str: str = None
|
||
arg0_kind: int = arg0.kind()
|
||
if arg0_kind == ast.ASTKind.Constant:
|
||
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(arg0)
|
||
if cn.const_kind == ast.CONST_STR:
|
||
fmt_str = cn.str_val
|
||
|
||
if fmt_str is None:
|
||
return
|
||
|
||
fmt_ptr: llvmlite.Value | t.CPtr = self.Gen.ExprGenConst.create_global_string(
|
||
builder, pool, mod, fmt_str, trans)
|
||
if fmt_ptr is None:
|
||
return
|
||
|
||
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||
|
||
# 翻译额外参数并链接
|
||
prev: llvmlite.Value | t.CPtr = fmt_ptr
|
||
for ai in range(1, can):
|
||
arg: ast.AST | t.CPtr = cargs.get(ai)
|
||
if arg is not None:
|
||
arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, arg, None, 0, trans)
|
||
if arg_val is not None:
|
||
# C ABI integer promotion: i8/i16 → i32(printf 变参函数要求)
|
||
arg_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(arg_val.Ty)
|
||
if arg_bits != 0 and arg_bits < 32:
|
||
arg_val = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, i32_ty, arg)
|
||
# C ABI float promotion: float → double(printf 变参函数要求)
|
||
arg_fbits: int = self.Gen.ExprGenBase.get_llvm_float_bits(arg_val.Ty)
|
||
if arg_fbits != 0 and arg_fbits < 64:
|
||
double_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool)
|
||
arg_val = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, double_ty, arg)
|
||
arg_val.Next = None
|
||
prev.Next = arg_val
|
||
prev = arg_val
|
||
prev.Next = None
|
||
|
||
# is_variadic=1: 生成带显式函数类型签名的 call(如 call i32 (i8*, ...) @printf),
|
||
# 让 llc 识别为 variadic 调用,生成正确的 Win64 ABI 代码(浮点参数同时传 XMM 和整数寄存器)
|
||
llvmlite.build_call(builder, "printf", fmt_ptr, can, i32_ty, 1)
|
||
|
||
|
||
def translate_print_call(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
cl: ast.Call | t.CPtr,
|
||
trans: HT.Translator | t.CPtr = None) -> None:
|
||
"""翻译 print 调用(类型感知格式化 + 默认换行)"""
|
||
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
|
||
if cargs is None:
|
||
return
|
||
|
||
FMT_BUF_SIZE: sizet = 256
|
||
fmt_buf: bytes = stdlib.malloc(FMT_BUF_SIZE)
|
||
if fmt_buf is None:
|
||
return
|
||
fmt_buf[0] = '\0'
|
||
|
||
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||
i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
|
||
dbl_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool)
|
||
|
||
can: sizet = len(cargs)
|
||
arg_head: llvmlite.Value | t.CPtr = None
|
||
arg_tail: llvmlite.Value | t.CPtr = None
|
||
arg_count: int = 1 # 格式串本身是第 1 个 printf 参数
|
||
|
||
for ai in range(can):
|
||
arg: ast.AST | t.CPtr = cargs.get(ai)
|
||
if arg is None:
|
||
continue
|
||
arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, arg, None, 0, trans)
|
||
if arg_val is None or arg_val.Ty is None:
|
||
# fail-fast:print 参数翻译失败必须终止编译,绝不在格式串写
|
||
# 误导为数据问题而非编译器 bug。
|
||
VLogger.error(f"print 参数翻译失败(表达式返回 None): [arg={ai}]", "PRINT")
|
||
self.Gen.TypeGenErr.fatal_error(arg, "print 参数翻译失败(表达式返回 None)", "TypeError")
|
||
return
|
||
|
||
# 数组名(如 print(l),l: t.CArray[char, N]):
|
||
# translate_value 会 load 出数组值([N x T]),print 无法格式化;
|
||
# 按数组退化语义取数组 alloca 地址——字符数组 → %s(打印字符串内容),
|
||
# 其他元素类型 → 0x%llx(打印数组地址)。
|
||
array_ptr: llvmlite.Value | t.CPtr = None
|
||
array_elem_bits: int = 0
|
||
if arg.kind() == ast.ASTKind.Name and trans is not None:
|
||
anm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arg)
|
||
if anm.id is not None:
|
||
arr_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var(
|
||
trans.SymTab, anm.id)
|
||
if arr_alloca is not None and arr_alloca.Ty is not None \
|
||
and self.Gen.ExprGenBase.is_ptr_type(arr_alloca.Ty) != 0:
|
||
arr_pointee: llvmlite.LLVMType | t.CPtr = arr_alloca.Ty.Pointee
|
||
if arr_pointee is not None:
|
||
match arr_pointee:
|
||
case llvmlite.LLVMType.Array(arr_et, arr_n):
|
||
array_ptr = arr_alloca
|
||
array_elem_bits = self.Gen.ExprGenBase.get_llvm_type_bits(arr_et)
|
||
case _:
|
||
pass
|
||
|
||
token: str = None
|
||
chain_arg: int = 1 # 1=该 token 消耗一个参数,0=纯文本
|
||
arg_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(arg_val.Ty)
|
||
arg_fbits: int = self.Gen.ExprGenBase.get_llvm_float_bits(arg_val.Ty)
|
||
|
||
if array_ptr is not None:
|
||
# 数组退化:字符数组 → %s(bitcast [N x i8]* 到 i8*);其他 → 0x%llx
|
||
if array_elem_bits == 8:
|
||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(
|
||
pool, llvmlite.Int8(pool))
|
||
token = "%s"
|
||
arg_val = llvmlite.build_bitcast(builder, array_ptr, i8_ptr_ty)
|
||
else:
|
||
token = "0x%llx"
|
||
arg_val = llvmlite.build_ptrtoint(builder, array_ptr, i64_ty)
|
||
elif self.Gen.ExprGenBase.is_ptr_type(arg_val.Ty) != 0:
|
||
# i8*(str/bytes)→ %s;其他指针 → 0x%llx
|
||
pointee: llvmlite.LLVMType | t.CPtr = arg_val.Ty.Pointee
|
||
if pointee is not None and self.Gen.ExprGenBase.get_llvm_type_bits(pointee) == 8:
|
||
token = "%s"
|
||
else:
|
||
token = "0x%llx"
|
||
arg_val = llvmlite.build_ptrtoint(builder, arg_val, i64_ty)
|
||
elif arg_bits != 0:
|
||
if arg_bits == 1:
|
||
token = "%d"
|
||
arg_val = llvmlite.build_zext(builder, arg_val, i32_ty)
|
||
elif arg_bits == 8:
|
||
token = "%d"
|
||
arg_val = llvmlite.build_sext(builder, arg_val, i32_ty)
|
||
elif arg_bits == 16:
|
||
token = "%d"
|
||
arg_val = llvmlite.build_sext(builder, arg_val, i32_ty)
|
||
elif arg_bits == 32:
|
||
token = "%d"
|
||
else:
|
||
token = "%lld"
|
||
elif arg_fbits != 0:
|
||
token = "%f"
|
||
if arg_fbits < 64:
|
||
arg_val = llvmlite.build_fpext(builder, arg_val, dbl_ty)
|
||
else:
|
||
# 结构体值/数组/函数等 → "(unknown)",不传参
|
||
token = "(unknown)"
|
||
chain_arg = 0
|
||
|
||
# 追加格式 token
|
||
if string.strlen(fmt_buf) < FMT_BUF_SIZE - 16:
|
||
viperlib.snprintf(fmt_buf + string.strlen(fmt_buf), 16, "%s", token)
|
||
# 链接参数
|
||
if chain_arg != 0:
|
||
arg_val.Next = None
|
||
if arg_tail is None:
|
||
arg_head = arg_val
|
||
else:
|
||
arg_tail.Next = arg_val
|
||
arg_tail = arg_val
|
||
arg_count += 1
|
||
|
||
# 追加默认换行(Python print 默认 end="\n")
|
||
if string.strlen(fmt_buf) < FMT_BUF_SIZE - 2:
|
||
viperlib.snprintf(fmt_buf + string.strlen(fmt_buf), 2, "\n")
|
||
|
||
fmt_ptr: llvmlite.Value | t.CPtr = self.Gen.ExprGenConst.create_global_string(
|
||
builder, pool, mod, fmt_buf, trans)
|
||
stdlib.free(fmt_buf)
|
||
if fmt_ptr is None:
|
||
return
|
||
fmt_ptr.Next = arg_head
|
||
# is_variadic=1: 带显式函数类型签名(C ABI 变参调用)
|
||
llvmlite.build_call(builder, "printf", fmt_ptr, arg_count, i32_ty, 1)
|
||
|
||
|
||
def init_func_table(self, pool: memhub.MemBuddy | t.CPtr,
|
||
max_count: int) -> GenTypes.FuncEntry | t.CPtr:
|
||
"""分配并清零函数表数组"""
|
||
size: sizet = max_count * GenTypes.FuncEntry.__sizeof__()
|
||
funcs_ptr: GenTypes.FuncEntry | t.CPtr = pool.alloc(size)
|
||
if funcs_ptr is not None:
|
||
string.memset(funcs_ptr, 0, size)
|
||
return funcs_ptr
|
||
|
||
|
||
def find_func_in_table(self, funcs: GenTypes.FuncEntry | t.CPtr,
|
||
func_count: int,
|
||
name: str,
|
||
owner_sha1: str = None) -> llvmlite.Function | t.CPtr:
|
||
"""在函数表中按名称查找,返回 Function 指针或 None
|
||
|
||
owner_sha1: 当前模块 SHA1。非 None 时"本模块函数优先"——表里同名条目
|
||
可能同时含本模块函数与依赖 stub 注入的外来函数(LoadDepVpiIntoModule
|
||
在 forward_declare_functions 之前把依赖模块同名函数以裸名注册进本文件
|
||
_funcs,槽位在前;本模块条目注册在后)。本模块函数 mangled 名为
|
||
"{owner_sha1}.{name}",按其 16 位前缀优先返回;无本模块条目
|
||
(纯 from-import/外部 stub)时回落首个同名条目(旧语义)。
|
||
"""
|
||
if name is None or funcs is None:
|
||
return None
|
||
entry_size: sizet = GenTypes.FuncEntry.__sizeof__()
|
||
# 单遍扫描(合并原 owner 优先遍 + 通用遍,语义完全一致但省一半遍历):
|
||
# 扫描中同时记录"首个同裸名条目"作通用兜底;一旦发现本模块条目
|
||
# (mangled 名以 "{owner_sha1}." 开头,16 位前缀 + '.')立即返回。
|
||
# 等价性:原两遍先做 owner 前缀遍(命中即返),再从头做首个同裸名遍;
|
||
# 本单遍按同一顺序扫描,owner 命中时机相同,未命中时返回的首个同裸名
|
||
# 条目也与原第二遍一致(含 entry.Func 为 None 时返回 None 的旧语义)。
|
||
# 前缀相同但非 mangled 名(CExport 等裸名条目名不含 '.')不命中,
|
||
# 由首个同裸名兜底返回(同旧语义)。
|
||
fallback_entry: GenTypes.FuncEntry | t.CPtr = None
|
||
for i in range(func_count):
|
||
entry_addr: uint64 = uint64(funcs) + i * entry_size
|
||
entry: GenTypes.FuncEntry | t.CPtr = (GenTypes.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
|
||
if entry is not None and entry.Name is not None:
|
||
if string.strcmp(entry.Name, name) == 0:
|
||
if fallback_entry is None:
|
||
fallback_entry = entry
|
||
if entry.Func is not None and owner_sha1 is not None:
|
||
fn_nm_o: str = llvmlite.function_get_name(entry.Func)
|
||
if fn_nm_o is not None:
|
||
if string.strncmp(fn_nm_o, owner_sha1, 16) == 0 and fn_nm_o[16] == '.':
|
||
return entry.Func
|
||
if fallback_entry is not None:
|
||
return fallback_entry.Func
|
||
return None
|
||
|
||
|
||
def add_func_to_table(self, funcs: GenTypes.FuncEntry | t.CPtr,
|
||
func_count: int,
|
||
name: str,
|
||
func: llvmlite.Function | t.CPtr,
|
||
max_count: int,
|
||
defaults: t.CPtr = None,
|
||
default_count: int = 0,
|
||
param_count: int = 0,
|
||
pool: memhub.MemBuddy | t.CPtr = None,
|
||
def_sha1: str = None) -> int:
|
||
"""添加函数到函数表,返回 0 成功
|
||
|
||
Args:
|
||
defaults: ast.Arguments.defaults 列表节点指针,None=无默认值
|
||
default_count: 默认值数量(len(defaults))
|
||
param_count: 形参数量(不含 self,len(args.args))
|
||
pool: 内存池(保留兼容参数;Spec 由 arena/PermPool 分配)
|
||
"""
|
||
if name is None or func is None or funcs is None:
|
||
return 1
|
||
if func_count >= max_count:
|
||
return 1
|
||
entry_size: sizet = GenTypes.FuncEntry.__sizeof__()
|
||
entry_addr: uint64 = uint64(funcs) + func_count * entry_size
|
||
entry: GenTypes.FuncEntry | t.CPtr = (GenTypes.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
|
||
entry.Name = name
|
||
entry.Func = func
|
||
entry.Defaults = defaults
|
||
entry.DefaultCount = default_count
|
||
entry.ParamCount = param_count
|
||
# [S3 条目双写] Spec 在形参 add_param 完成后由 update_global_func_spec 填
|
||
entry.Spec = None
|
||
# 同时注册到全局函数表(供跨模块 vtable 初始化查找)
|
||
self._register_global_func(name, func, pool)
|
||
# 同时注册到全局默认参数表(供跨模块调用时填充默认值)
|
||
if default_count > 0:
|
||
self._register_global_defaults(name, defaults, default_count, param_count, def_sha1)
|
||
return 0
|
||
|
||
|
||
def _init_global_func_table(self) -> int:
|
||
"""初始化全局函数表(用 stdlib.malloc 分配,生命周期=整个程序)"""
|
||
if self.GlobalFuncs is not None:
|
||
return 1
|
||
size: sizet = GLOBAL_FUNC_MAX * GenTypes.FuncEntry.__sizeof__()
|
||
self.GlobalFuncs = CompilerFactory.factory.PermPool.alloc(size)
|
||
if self.GlobalFuncs is None:
|
||
return 0
|
||
string.memset(self.GlobalFuncs, 0, size)
|
||
self.GlobalFuncCount = 0
|
||
return 1
|
||
|
||
|
||
def _register_global_func(self, name: str, func: llvmlite.Function | t.CPtr,
|
||
pool: memhub.MemBuddy | t.CPtr = None) -> int:
|
||
"""注册函数到全局表(已存在则跳过),返回 0 成功
|
||
|
||
直接操作全局表,不调用 add_func_to_table,避免递归。
|
||
"""
|
||
if name is None or func is None:
|
||
return 1
|
||
if self._init_global_func_table() == 0:
|
||
return 1
|
||
# 已存在则跳过(避免重复)
|
||
if self.find_func_in_table(self.GlobalFuncs, self.GlobalFuncCount, name) is not None:
|
||
return 0
|
||
if self.GlobalFuncCount >= GLOBAL_FUNC_MAX:
|
||
return 1
|
||
# 直接写入全局表(不调用 add_func_to_table,避免递归)
|
||
entry_size: sizet = GenTypes.FuncEntry.__sizeof__()
|
||
entry_addr: uint64 = uint64(self.GlobalFuncs) + self.GlobalFuncCount * entry_size
|
||
entry: GenTypes.FuncEntry | t.CPtr = (GenTypes.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
|
||
# Name 深拷贝到 stdlib 区:全局表跨文件永久存活,pool 内名字会被 1b 每文件
|
||
# reset_to(mark1) 回收导致悬空(vtable 生成 find_func_global 后 strcmp 崩溃)
|
||
name_len: sizet = string.strlen(name)
|
||
name_copy: str = CompilerFactory.factory.PermPool.alloc(name_len + 1)
|
||
if name_copy is None:
|
||
return 1
|
||
string.strcpy(name_copy, name)
|
||
entry.Name = name_copy
|
||
entry.Func = func
|
||
# [S3 条目双写] Spec 待 update_global_func_spec 填(形参未 add 完)
|
||
entry.Spec = None
|
||
# Spec 不在此生成:函数参数在 add_func_to_table 之后才添加,
|
||
# 需由调用方在参数添加完成后调用 update_global_func_spec 补全。
|
||
self.GlobalFuncCount += 1
|
||
return 0
|
||
|
||
|
||
def update_global_func_spec(self, name: str,
|
||
func: llvmlite.Function | t.CPtr) -> int:
|
||
"""更新全局函数表的 Spec(在函数参数全部添加完成后调用)
|
||
|
||
调用时机:add_func_to_table 注册后、llvmlite.add_param 全部执行完。
|
||
用 NewTypeFunc 构造整签名 Spec(PermPool 驻留,跨 1b reset 安全),
|
||
供 vtable 生成在 func 被 1b reset 后经 SpecToLLVMText 派生类型文本。
|
||
"""
|
||
if name is None or func is None:
|
||
return 1
|
||
entry: GenTypes.FuncEntry | t.CPtr = self.find_func_entry_global(name)
|
||
if entry is None:
|
||
return 1
|
||
entry.Spec = self._build_func_spec(func)
|
||
return 0
|
||
|
||
|
||
# ============================================================
|
||
# _build_func_spec - 由函数对象构造整签名 TypeSpec(S3 条目双写)
|
||
#
|
||
# Kind=TS_FUNC:Ret + 形参 Spec 数组 + ParamCount + IsVarArg。必须在形参
|
||
# 全部 add_param 完成后调用。
|
||
# 参数沿 `llvmlite.function_get_param_head` 的 Param 链表**两遍遍历**(先计数
|
||
# 再填充)——llvmlite 无按下标取参,且无法预知长度以一次分配。
|
||
# 注意与 `TSpec.SpecFromLLVMType` 的 Func 分支的区别:后者只能看到
|
||
# `LLVMType.Func`(**不含变参信息**,恒置 IsVarArg=0),故此处直接用
|
||
# `NewTypeFunc(..., func.IsVarArg)` 构造。
|
||
# 失败(池分配失败等)返回 None;调用方保留 None,不静默造伪 spec。
|
||
# ============================================================
|
||
def _build_func_spec(self, func: llvmlite.Function | t.CPtr) -> TSpec.TypeSpec | t.CPtr:
|
||
"""由函数对象构造整签名 TypeSpec,失败返回 None"""
|
||
if func is None:
|
||
return None
|
||
arena: TSpec.TypeSpecArena | t.CPtr = self.Gen.TypeGenBase.ensure_spec_arena()
|
||
if arena is None:
|
||
return None
|
||
ret_s: TSpec.TypeSpec | t.CPtr = TSpec.SpecFromLLVMType(
|
||
arena, llvmlite.function_get_ret_ty(func))
|
||
if ret_s is None:
|
||
return None
|
||
# 第一遍:计数
|
||
cnt: int = 0
|
||
cur: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(func)
|
||
while cur is not None and cnt < 256:
|
||
cnt += 1
|
||
cur = llvmlite.param_get_next(cur)
|
||
# 第二遍:逐个构造并写入连续参数数组
|
||
params_arr: sizet | t.CPtr = None
|
||
if cnt > 0:
|
||
params_arr = CompilerFactory.factory.PermPool.alloc(8 * cnt)
|
||
if params_arr is None:
|
||
return None
|
||
cur = llvmlite.function_get_param_head(func)
|
||
i: int = 0
|
||
while cur is not None and i < cnt:
|
||
ps: TSpec.TypeSpec | t.CPtr = TSpec.SpecFromLLVMType(
|
||
arena, llvmlite.param_get_ty(cur))
|
||
if ps is None:
|
||
return None
|
||
slot: sizet | t.CPtr = (sizet | t.CPtr)(
|
||
t.CVoid(uint64(params_arr) + uint64(i * 8), t.CPtr))
|
||
if slot is None:
|
||
return None
|
||
slot[0] = sizet(ps)
|
||
cur = llvmlite.param_get_next(cur)
|
||
i += 1
|
||
return TSpec.NewTypeFunc(arena, ret_s, params_arr, cnt, func.IsVarArg)
|
||
|
||
|
||
def find_func_global(self, name: str) -> llvmlite.Function | t.CPtr:
|
||
"""在全局函数表中按名称查找,返回 Function 指针或 None"""
|
||
if name is None or self.GlobalFuncs is None:
|
||
return None
|
||
return self.find_func_in_table(self.GlobalFuncs, self.GlobalFuncCount, name)
|
||
|
||
|
||
def find_func_entry_global(self, name: str) -> GenTypes.FuncEntry | t.CPtr:
|
||
"""在全局函数表中按名称查找,返回完整 FuncEntry(含 Spec)或 None"""
|
||
if name is None or self.GlobalFuncs is None:
|
||
return None
|
||
entry_size: sizet = GenTypes.FuncEntry.__sizeof__()
|
||
for i in range(self.GlobalFuncCount):
|
||
entry_addr: uint64 = uint64(self.GlobalFuncs) + i * entry_size
|
||
entry: GenTypes.FuncEntry | t.CPtr = (GenTypes.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
|
||
if entry.Name is not None:
|
||
if string.strcmp(entry.Name, name) == 0:
|
||
return entry
|
||
return None
|
||
|
||
|
||
def _init_global_defaults_table(self) -> int:
|
||
"""初始化全局默认参数表"""
|
||
if self.GlobalDefaults is not None:
|
||
return 1
|
||
size: sizet = GLOBAL_DEFAULTS_MAX * GenTypes.FuncDefaultsEntry.__sizeof__()
|
||
self.GlobalDefaults = CompilerFactory.factory.PermPool.alloc(size)
|
||
if self.GlobalDefaults is None:
|
||
return 0
|
||
string.memset(self.GlobalDefaults, 0, size)
|
||
self.GlobalDefaultsCount = 0
|
||
return 1
|
||
|
||
|
||
def _register_global_defaults(self, name: str,
|
||
defaults: t.CPtr,
|
||
default_count: int,
|
||
param_count: int,
|
||
def_sha1: str = None) -> int:
|
||
"""注册函数默认参数到全局表,返回 0 成功
|
||
|
||
注册时提取每个默认值 Constant 的常量快照到 stdlib(ConstKinds/ConstInts/ConstStrs),
|
||
跨模块调用时优先用快照重建常量 IR,避免读取被 reset 回收的 pool 内 AST。
|
||
|
||
def_sha1:**定义该函数的模块 SHA1**。依赖注入路径(VpiReader)必须显式传入,
|
||
否则会退回 CurrentModuleSha1 —— 注入期它是**导入方**,会把被依赖模块函数的
|
||
默认值挂到导入方名下(如 mm.init 的 2 个默认值挂到 usb)→ usb 的
|
||
`uhci.init(io_base)` 经 find_func_defaults("init", usb_sha) 命中该错账条目
|
||
而被补 2 个 i32 0(N17 真因;模块函数表的"按定义模块限定查找"救不了这条
|
||
全局表路径,因为该处 found_func 仍为 None、交叉校验被整体跳过)。
|
||
"""
|
||
if name is None or defaults is None:
|
||
return 1
|
||
if self._init_global_defaults_table() == 0:
|
||
return 1
|
||
# 限定键 = **定义该函数的模块 SHA1**:同一函数名在不同模块各存一条,查询时
|
||
# 按「名 + 定义模块」精确匹配,消除跨模块同名串味。def_sha1 由依赖注入
|
||
# 路径显式传入被依赖模块自身 sha1;非注入路径(本模块真实定义)取
|
||
# CurrentModuleSha1(此时它就是定义模块)。
|
||
cur_sha: str = def_sha1
|
||
if cur_sha is None and self.Gen is not None and self.Gen.TypeGenBase is not None:
|
||
cur_sha = self.Gen.TypeGenBase.CurrentModuleSha1
|
||
# 同模块同名已存在则跳过
|
||
if self.find_func_defaults(name, cur_sha) is not None:
|
||
return 0
|
||
if self.GlobalDefaultsCount >= GLOBAL_DEFAULTS_MAX:
|
||
return 1
|
||
entry_size: sizet = GenTypes.FuncDefaultsEntry.__sizeof__()
|
||
entry_addr: uint64 = uint64(self.GlobalDefaults) + self.GlobalDefaultsCount * entry_size
|
||
entry: GenTypes.FuncDefaultsEntry | t.CPtr = (GenTypes.FuncDefaultsEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
|
||
# Name 深拷贝到 stdlib(全局表跨文件永久存活)
|
||
nm_len: sizet = string.strlen(name)
|
||
nm_copy: str = CompilerFactory.factory.PermPool.alloc(nm_len + 1)
|
||
if nm_copy is None:
|
||
return 1
|
||
string.strcpy(nm_copy, name)
|
||
entry.Name = nm_copy
|
||
entry.ModuleSha1 = None
|
||
if cur_sha is not None:
|
||
sh_len: sizet = string.strlen(cur_sha)
|
||
sh_copy: str = CompilerFactory.factory.PermPool.alloc(sh_len + 1)
|
||
if sh_copy is not None:
|
||
string.strcpy(sh_copy, cur_sha)
|
||
entry.ModuleSha1 = sh_copy
|
||
entry.Defaults = defaults
|
||
entry.DefaultCount = default_count
|
||
entry.ParamCount = param_count
|
||
# 范围防御:default_count 异常(vpi tree 损坏时 len 垃圾大数)时放弃
|
||
# 提取快照(调用方哨兵已拦截,此为第二道),避免 alloc(垃圾) + 数组
|
||
# 越界写 perm_pool 覆盖当前模块 AST/表(SlotsBugTest 崩溃根因候选)。
|
||
if default_count > 128:
|
||
entry.Defaults = None
|
||
entry.DefaultCount = 0
|
||
return 0
|
||
# 提取常量快照到 stdlib
|
||
if default_count > 0:
|
||
kinds: int | t.CPtr = CompilerFactory.factory.PermPool.alloc(default_count * 4)
|
||
ints: int64 | t.CPtr = CompilerFactory.factory.PermPool.alloc(default_count * 8)
|
||
strs: sizet | t.CPtr = CompilerFactory.factory.PermPool.alloc(default_count * 8)
|
||
if kinds is not None and ints is not None and strs is not None:
|
||
string.memset(kinds, 0, default_count * 4)
|
||
string.memset(ints, 0, default_count * 8)
|
||
string.memset(strs, 0, default_count * 8)
|
||
dl: list[ast.AST | t.CPtr] | t.CPtr = (list[ast.AST | t.CPtr] | t.CPtr)(t.CVoid(uint64(defaults), t.CPtr))
|
||
di: int
|
||
for di in range(default_count):
|
||
dnode: ast.AST | t.CPtr = dl.get(di)
|
||
if dnode is not None and dnode.kind() == ast.ASTKind.Constant:
|
||
dcn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(dnode)
|
||
kinds[di] = dcn.const_kind
|
||
ints[di] = dcn.int_val
|
||
if dcn.const_kind == ast.CONST_STR and dcn.str_val is not None:
|
||
slen: sizet = string.strlen(dcn.str_val)
|
||
scopy: str = CompilerFactory.factory.PermPool.alloc(slen + 1)
|
||
if scopy is not None:
|
||
string.strcpy(scopy, dcn.str_val)
|
||
strs[di] = sizet(scopy)
|
||
elif dnode is not None and dnode.kind() == ast.ASTKind.Name:
|
||
# CDefine Name 引用默认值(如 share: ULONG = SHARE_READ):
|
||
# 注册时求值 CDefine 存快照——否则跨模块重建时快照为空
|
||
# → "跨模块默认参数无法重建"(FileIoTest File.__init__ 根因)。
|
||
# 仅支持已注册的整型 CDefine;未注册保持 kinds=0(重建时
|
||
# 仍 fail-fast,绝不静默回退)。
|
||
dnm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(dnode)
|
||
if dnm.id is not None:
|
||
cdef_v: int = self.Gen.TypeGenCDef.lookup_cdefine_constant(dnm.id)
|
||
if self.Gen.TypeGenCDef.is_cdefine_found() != 0:
|
||
kinds[di] = ast.CONST_INT
|
||
ints[di] = cdef_v
|
||
elif dnode is not None and dnode.kind() == ast.ASTKind.UnaryOp:
|
||
# 一元字面量默认值(如 ex3: int = -1):AST 是
|
||
# UnaryOp(USub, Constant(1)),不是 Constant —— 此前无此分支
|
||
# → kinds[di] 保持 0 → 快照重建失败 → "跨模块默认参数无法
|
||
# 重建(快照缺失,默认值需为简单常量)"(AppGui.top_index
|
||
# 的 ex3 = -1 根因)。只对"操作数是整型 Constant"求值,
|
||
# 其它(浮点取负 / 取负变量)保持 kinds=0 → 重建时 fail-fast。
|
||
du: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(dnode)
|
||
if du.operand is not None and du.operand.kind() == ast.ASTKind.Constant:
|
||
doc: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(du.operand)
|
||
if doc.const_kind == ast.CONST_INT:
|
||
if du.op == ast.OpKind.USub:
|
||
kinds[di] = ast.CONST_INT
|
||
ints[di] = -doc.int_val
|
||
elif du.op == ast.OpKind.UAdd:
|
||
kinds[di] = ast.CONST_INT
|
||
ints[di] = doc.int_val
|
||
elif du.op == ast.OpKind.Invert:
|
||
kinds[di] = ast.CONST_INT
|
||
ints[di] = ~doc.int_val
|
||
entry.ConstKinds = kinds
|
||
entry.ConstInts = ints
|
||
entry.ConstStrs = strs
|
||
self.GlobalDefaultsCount += 1
|
||
return 0
|
||
|
||
|
||
def find_func_defaults(self, name: str,
|
||
module_sha1: str = None) -> GenTypes.FuncDefaultsEntry | t.CPtr:
|
||
"""按函数名(可选按定义模块 SHA1)查找默认参数信息,返回 FuncDefaultsEntry 或 None
|
||
|
||
module_sha1 非 None 时要求条目定义模块完全一致(限定名匹配,消除跨模块同名串味);
|
||
为 None 时退化为按名匹配(兼容旧调用点)。
|
||
"""
|
||
if name is None or self.GlobalDefaults is None:
|
||
return None
|
||
entry_size: sizet = GenTypes.FuncDefaultsEntry.__sizeof__()
|
||
for i in range(self.GlobalDefaultsCount):
|
||
entry_addr: uint64 = uint64(self.GlobalDefaults) + i * entry_size
|
||
entry: GenTypes.FuncDefaultsEntry | t.CPtr = (GenTypes.FuncDefaultsEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
|
||
if entry.Name is None:
|
||
continue
|
||
if string.strcmp(entry.Name, name) != 0:
|
||
continue
|
||
if module_sha1 is not None:
|
||
if entry.ModuleSha1 is None:
|
||
continue
|
||
if string.strcmp(entry.ModuleSha1, module_sha1) != 0:
|
||
continue
|
||
return entry
|
||
return None
|
||
|
||
|
||
def _build_const_from_snapshot(self, pool: memhub.MemBuddy | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
gd_entry: GenTypes.FuncDefaultsEntry | t.CPtr,
|
||
di: int,
|
||
trans: HT.Translator | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||
"""从快照重建第 di 个默认值常量 IR"""
|
||
if gd_entry is None or gd_entry.ConstKinds is None or gd_entry.ConstInts is None:
|
||
return None
|
||
if di < 0 or di >= gd_entry.DefaultCount:
|
||
return None
|
||
kind: int = gd_entry.ConstKinds[di]
|
||
ival: int64 = gd_entry.ConstInts[di]
|
||
if kind == ast.CONST_INT:
|
||
if ival > 2147483647 or ival < -2147483648:
|
||
return llvmlite.const_int64(pool, ival)
|
||
return llvmlite.const_int32(pool, ival)
|
||
elif kind == ast.CONST_BOOL:
|
||
if ival != 0:
|
||
return llvmlite.const_int32(pool, 1)
|
||
return llvmlite.const_int32(pool, 0)
|
||
elif kind == ast.CONST_NONE:
|
||
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
|
||
return llvmlite.ConstNull(pool, i8_ptr_ty, "null")
|
||
elif kind == ast.CONST_STR:
|
||
if gd_entry.ConstStrs is not None and gd_entry.ConstStrs[di] != 0:
|
||
sv: str = (str | t.CPtr)(t.CVoid(gd_entry.ConstStrs[di], t.CPtr))
|
||
return self.Gen.ExprGenConst.create_global_string(builder, pool, mod, sv, trans)
|
||
# 无法重建的(如 CONST_FLOAT/复杂表达式)返回 None,调用方回退到 AST
|
||
return None
|
||
|
||
|
||
def find_func_entry_in_table(self, funcs: GenTypes.FuncEntry | t.CPtr,
|
||
func_count: int,
|
||
name: str) -> GenTypes.FuncEntry | t.CPtr:
|
||
"""在函数表中按名称查找,返回完整 FuncEntry 或 None"""
|
||
if name is None or funcs is None:
|
||
return None
|
||
entry_size: sizet = GenTypes.FuncEntry.__sizeof__()
|
||
for i in range(func_count):
|
||
entry_addr: uint64 = uint64(funcs) + i * entry_size
|
||
entry: GenTypes.FuncEntry | t.CPtr = (GenTypes.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
|
||
if entry.Name is not None:
|
||
if string.strcmp(entry.Name, name) == 0:
|
||
return entry
|
||
return None
|
||
|
||
def find_func_entry_in_table_owned(self, funcs: GenTypes.FuncEntry | t.CPtr,
|
||
func_count: int,
|
||
name: str,
|
||
owner_sha1: str) -> GenTypes.FuncEntry | t.CPtr:
|
||
"""按「裸名 + 定义模块 SHA1」查找函数表条目,返回 FuncEntry 或 None
|
||
|
||
函数表以**裸名**登记,且 LoadDepVpiIntoModule 会把依赖模块的同名函数
|
||
(同样裸名)注入到本模块表 —— 裸名首命中会跨模块串味:usb.vp 的
|
||
`uhci.init(io_base)`(1 形参)会命中先注入的 `mm.init`(5 形参/2 默认值)
|
||
→ 调用点被补 2 个 `i32 0` → call 3 实参 vs declare/define 1 形参(N17)。
|
||
故以 `entry.Func` 的 mangled 名("{定义模块 sha1}.{name}")前缀限定定义
|
||
模块;owner_sha1 为 None(模块名不可解)时退化为裸名首命中(旧语义,
|
||
避免丢失合法的默认参数填充)。
|
||
"""
|
||
if name is None or funcs is None:
|
||
return None
|
||
entry_size: sizet = GenTypes.FuncEntry.__sizeof__()
|
||
for i in range(func_count):
|
||
entry_addr: uint64 = uint64(funcs) + i * entry_size
|
||
entry: GenTypes.FuncEntry | t.CPtr = (GenTypes.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
|
||
if entry is None or entry.Name is None:
|
||
continue
|
||
if string.strcmp(entry.Name, name) != 0:
|
||
continue
|
||
if owner_sha1 is None:
|
||
return entry
|
||
if entry.Func is not None:
|
||
fn_nm_o: str = llvmlite.function_get_name(entry.Func)
|
||
if fn_nm_o is not None:
|
||
if string.strncmp(fn_nm_o, owner_sha1, 16) == 0 and fn_nm_o[16] == '.':
|
||
return entry
|
||
return None
|
||
|
||
|
||
def NewExprCallHandle(self, pool: memhub.MemBuddy | t.CPtr,
|
||
trans: HT.Translator | t.CPtr) -> ExprCallHandle | t.CPtr:
|
||
h: ExprCallHandle | t.CPtr = pool.alloc(ExprCallHandle.__sizeof__())
|
||
if h is None:
|
||
return None
|
||
string.memset(h, 0, ExprCallHandle.__sizeof__())
|
||
h.Trans = trans
|
||
return h
|
||
|
||
|
||
# ============================================================
|
||
# ExprCallHandle - 函数调用处理器(自 HandlesExprCall 迁入)
|
||
#
|
||
# HandleCall / HandlePrintfCall / HandlePrintCall 提供 trans 接口,
|
||
# 内部委托 GenApi.translate_call 等。
|
||
# ============================================================
|
||
@t.NoVTable
|
||
class ExprCallHandle(HT.Mixin):
|
||
"""函数调用处理器:继承 Mixin 获得 Trans 回指针"""
|
||
|
||
def __init__(self, trans: HT.Translator | t.CPtr):
|
||
self.Trans = trans
|
||
|
||
# ============================================================
|
||
# HandleCall - 翻译函数调用,返回 call 结果 Value
|
||
# ============================================================
|
||
def HandleCall(self, node: ast.AST | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||
"""翻译函数调用,从 self.Trans 获取共享状态"""
|
||
return GenApi.translate_call(
|
||
self.Trans.Pool, self.Trans._cur_builder, self.Trans.Module,
|
||
node,
|
||
self.Trans._funcs, self.Trans._func_count, self.Trans)
|
||
|
||
# ============================================================
|
||
# HandlePrintfCall - 翻译 printf 调用
|
||
# ============================================================
|
||
def HandlePrintfCall(self, cl: ast.Call | t.CPtr):
|
||
"""翻译 printf 调用,从 self.Trans 获取共享状态"""
|
||
GenApi.translate_printf_call(
|
||
self.Trans.Pool, self.Trans._cur_builder, self.Trans.Module,
|
||
cl, self.Trans)
|
||
|
||
# ============================================================
|
||
# HandlePrintCall - 翻译 print 调用
|
||
# ============================================================
|
||
def HandlePrintCall(self, cl: ast.Call | t.CPtr):
|
||
"""翻译 print 调用(类型感知格式化 + 默认换行)"""
|
||
GenApi.translate_print_call(
|
||
self.Trans.Pool, self.Trans._cur_builder, self.Trans.Module,
|
||
cl, self.Trans)
|
||
|