- @t.NoVTable class X → novirtual class X
- t.CDefine = N → define N
- rawptr[X]、X | t.CPtr → X*
- t.CPtr → rawptr(裸指针标记)
- t.Callable[...] → callable[...]
- 去掉 if/elif 条件的行续反斜杠(改单行写法)
- w32.win32file.X → win32file.X(已 import as)
- core/__init__.vp 去掉未使用的 import t, c / from stdint import *
涉及:CompilerFactory、IncludesScanner、Repl、core/__init__、
Gen/Call/{CallGenBase,CallGenCBuiltin,CallGenCall,CallGenDispatch,CallGenLeafKit}、
Gen/Class/ClassGenGeneric。
1546 lines
80 KiB
Plaintext
1546 lines
80 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
|
||
from . import CallGenBase
|
||
|
||
|
||
# ============================================================
|
||
# CallGenLeafKit - CallGenMixin 拆分 3/9:EH/isinstance/闭包/print/函数表
|
||
# ============================================================
|
||
|
||
|
||
# ============================================================
|
||
# 常量
|
||
# ============================================================
|
||
define _CEXPORT_MAX = 256
|
||
define ASM_MAX_OPERANDS = 16
|
||
define ASM_TEXT_BUF_SIZE = 2048
|
||
define ASM_CONST_BUF_SIZE = 512
|
||
define ASM_ARGS_BUF_SIZE = 512
|
||
define ASM_LINE_BUF_SIZE = 4096
|
||
define LLVMIR_MAX_OPS = 16
|
||
define LLVMIR_TEMPLATE_BUF = 512
|
||
|
||
# ============================================================
|
||
# 全局函数表名索引(名 → 槽下标,开放寻址 | 线性探测)
|
||
#
|
||
# 槽数 = 2 * CallGenBase.GLOBAL_FUNC_MAX(2 的幂,负载 < 0.5,线性探测必然终止)。
|
||
# 值写成字面量 16384:模块级 t.CDefine 初始化式不能引用跨模块常量
|
||
# (跨模块 t.CDefine 只能在函数体内读),故与 CallGenBase.GLOBAL_FUNC_MAX 手工保持 2 倍关系。
|
||
# 槽存槽下标 + 1(0=空槽)。GlobalFuncs 在 PermPool 定长分配、只追加不重排、
|
||
# 从不 reset ⇒ 槽下标稳定;Built == GlobalFuncCount 才可信。
|
||
# ============================================================
|
||
define GLOBAL_FUNC_IDX_CAP = 16384
|
||
# 索引哈希常量(32 位 FNV-1a,与 StructGenMixin 范式一致)
|
||
define GFN_FNV_OFFSET = 2166136261
|
||
define GFN_FNV_PRIME = 16777619
|
||
define GFN_FNV_MASK = 4294967295
|
||
|
||
|
||
def _gfn_hash(name: str) -> uint64:
|
||
"""函数名 → 64 位哈希(32 位 FNV-1a,逐字节到 NUL 结束)"""
|
||
h: uint64 = uint64(GFN_FNV_OFFSET)
|
||
if name is None: return h
|
||
i: sizet = 0
|
||
while name[i] != '\0':
|
||
h = (h ^ uint64(int(name[i]))) * uint64(GFN_FNV_PRIME)
|
||
h = h & uint64(GFN_FNV_MASK)
|
||
i += 1
|
||
return h
|
||
|
||
|
||
def _gfn_idx_slot(idx_base: sizet*, si: sizet) -> sizet*:
|
||
"""取索引第 si 个槽(8 字节,存槽下标+1;0=空槽)"""
|
||
return (sizet*)(uint64(idx_base) + uint64(si) * 8)
|
||
|
||
|
||
def _gfn_idx_find(funcs: GenTypes.FuncEntry*,
|
||
idx_base: sizet*, cap: int, name: str) -> int:
|
||
"""在全局函数表名索引中探测 name,返回命中槽下标(>=0);未命中/不可用返回 -1"""
|
||
if funcs is None or idx_base is None or cap <= 0 or name is None:
|
||
return -1
|
||
h: uint64 = _gfn_hash(name)
|
||
mask: sizet = sizet(cap - 1)
|
||
si: sizet = sizet(h) & mask
|
||
entry_size: sizet = GenTypes.FuncEntry.__sizeof__()
|
||
i: int = 0
|
||
while i < cap:
|
||
slot: sizet* = _gfn_idx_slot(idx_base, si)
|
||
sv: sizet = slot[0]
|
||
if sv == 0: return -1
|
||
se: int = int(sv) - 1
|
||
entry_addr: uint64 = uint64(funcs) + se * entry_size
|
||
entry: GenTypes.FuncEntry* = GenTypes.FuncEntry*(entry_addr)
|
||
if entry is not None and entry.Name is not None:
|
||
if string.strcmp(entry.Name, name) == 0: return se
|
||
si = (si + 1) & mask
|
||
i += 1
|
||
return -1
|
||
|
||
|
||
def _gfn_idx_insert(idx_base: sizet*, cap: int, slot_index: int, name: str) -> int:
|
||
"""把 (name → slot_index) 记入索引;0=成功 / 1=失败"""
|
||
if idx_base is None or cap <= 0 or name is None:
|
||
return 1
|
||
h: uint64 = _gfn_hash(name)
|
||
mask: sizet = sizet(cap - 1)
|
||
si: sizet = sizet(h) & mask
|
||
i: int = 0
|
||
while i < cap:
|
||
slot: sizet* = _gfn_idx_slot(idx_base, si)
|
||
if slot[0] == 0:
|
||
slot[0] = sizet(slot_index + 1)
|
||
return 0
|
||
si = (si + 1) & mask
|
||
i += 1
|
||
return 1
|
||
|
||
|
||
# ============================================================
|
||
# CallGenLeafKit - EH/isinstance/闭包/print/函数表
|
||
# ============================================================
|
||
novirtual 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*) -> int:
|
||
"""返回 1=函数带 EH 输出参数 / 0=不带"""
|
||
if func is None:
|
||
return 0
|
||
cur_p: llvmlite.Param* = 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*,
|
||
pool: memhub.MemBuddy*,
|
||
mod: llvmlite.LLVMModule*,
|
||
trans: HT.Translator*,
|
||
func: llvmlite.Function*,
|
||
call_name: str,
|
||
head: llvmlite.Value*,
|
||
count: int,
|
||
ret_ty: llvmlite.LLVMType*,
|
||
is_variadic: int) -> llvmlite.Value*:
|
||
"""带 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* = llvmlite.Int8(pool)
|
||
i8_ptr_ty_g: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty_g)
|
||
i32_ty_g: llvmlite.LLVMType* = 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* = None
|
||
code_ptr: llvmlite.Value* = 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* = llvmlite.ConstNull(pool, i8_ptr_ty_g, "null")
|
||
zero_code_g: llvmlite.Value* = 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* = 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* = llvmlite.build_call(builder, call_name, head, count, ret_ty, is_variadic)
|
||
cur_func_g: llvmlite.Function* = trans._cur_func
|
||
if cur_func_g is None or null_msg_g is None: return result
|
||
msg_val_g: llvmlite.Value* = llvmlite.build_load(builder, i8_ptr_ty_g, msg_ptr)
|
||
if msg_val_g is None: return result
|
||
is_err_g: llvmlite.Value* = 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: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, cur_func_g, bb_buf_g)
|
||
viperlib.snprintf(bb_buf_g, 64, "eh.ok.%d", lc_g)
|
||
ok_bb_g: rawptr[llvmlite.BasicBlock] = 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* = 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* = 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* = 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* = 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*,
|
||
builder: llvmlite.IRBuilder*,
|
||
mod: llvmlite.LLVMModule*,
|
||
obj_node: ast.AST*,
|
||
cls_node: ast.AST*,
|
||
trans: HT.Translator* = None) -> llvmlite.Value*:
|
||
"""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* = 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* = obj_val
|
||
match obj_val.Ty:
|
||
case llvmlite.LLVMType.Ptr(inner_ty):
|
||
match inner_ty:
|
||
case llvmlite.LLVMType.Ptr(_):
|
||
loaded: llvmlite.Value* = 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* = llvmlite.Int8(pool)
|
||
i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty)
|
||
i8_ptr_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ptr_ty)
|
||
# 对象 vtable 指针惰性读取(首个 CVTable 类比较时执行一次)
|
||
vtable_ptr: llvmlite.Value* = None
|
||
vtable_ready: int = 0
|
||
res: llvmlite.Value* = None
|
||
cls_names: sizet* = 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 = rawptr(cls_names[ci])
|
||
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* = 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* = 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* = self._collect_subclass_vtable_classes(pool, cn)
|
||
if subs is not None:
|
||
k: int = 0
|
||
while subs[k] != 0:
|
||
scn: str = rawptr(subs[k])
|
||
if scn is not None:
|
||
sub_i8: llvmlite.Value* = self._make_vtable_ref_i8(pool, builder, mod, scn, trans)
|
||
if sub_i8 is not None:
|
||
cmp: llvmlite.Value* = 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*,
|
||
node: ast.AST*) -> sizet*:
|
||
"""从 isinstance 第二参数提取类名数组(Name→id / Attribute→attr / Tuple→遍历)"""
|
||
arr: sizet* = 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* = ast.Name*(node)
|
||
if nm.id is not None:
|
||
arr[0] = sizet(nm.id)
|
||
elif k == ast.ASTKind.Attribute:
|
||
at: ast.Attribute* = ast.Attribute*(node)
|
||
if at.attr is not None:
|
||
arr[0] = sizet(at.attr)
|
||
elif k == ast.ASTKind.Tuple:
|
||
tp: ast.Tuple* = ast.Tuple*(node)
|
||
elts: list[ast.AST*]* = tp.elts
|
||
if elts is not None:
|
||
n: sizet = len(elts)
|
||
for i in range(n):
|
||
if count >= 15:
|
||
break
|
||
elt: ast.AST* = elts.get(i)
|
||
if elt is None:
|
||
continue
|
||
ek: int = elt.kind()
|
||
if ek == ast.ASTKind.Name:
|
||
enm: ast.Name* = ast.Name*(elt)
|
||
if enm.id is not None:
|
||
arr[count] = sizet(enm.id)
|
||
count += 1
|
||
elif ek == ast.ASTKind.Attribute:
|
||
eat: ast.Attribute* = ast.Attribute*(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*,
|
||
class_name: str) -> sizet*:
|
||
"""反向 BFS 收集目标类及全部子类(含自身,仅 HasVTable==1),返回 0 结尾数组"""
|
||
if class_name is None:
|
||
return None
|
||
names: sizet* = pool.alloc(8 * (CallGenBase.ISINSTANCE_CLASS_MAX + 1))
|
||
queue: sizet* = pool.alloc(8 * CallGenBase.ISINSTANCE_CLASS_MAX)
|
||
visited: sizet* = pool.alloc(8 * CallGenBase.ISINSTANCE_CLASS_MAX)
|
||
if names is None or queue is None or visited is None:
|
||
return None
|
||
string.memset(names, 0, 8 * (CallGenBase.ISINSTANCE_CLASS_MAX + 1))
|
||
string.memset(queue, 0, 8 * CallGenBase.ISINSTANCE_CLASS_MAX)
|
||
string.memset(visited, 0, 8 * CallGenBase.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 = rawptr(cur_addr)
|
||
if cur is None:
|
||
continue
|
||
dup: int = 0
|
||
for vi in range(vcount):
|
||
va: sizet = visited[vi]
|
||
if va != 0:
|
||
vn: str = rawptr(va)
|
||
if vn is not None and string.strcmp(vn, cur) == 0:
|
||
dup = 1
|
||
break
|
||
if dup != 0:
|
||
continue
|
||
if vcount < CallGenBase.ISINSTANCE_CLASS_MAX:
|
||
visited[vcount] = sizet(cur)
|
||
vcount += 1
|
||
centry: GenTypes.StructEntry* = self.Gen.StructGen.find_struct(cur)
|
||
if centry is not None and centry.HasVTable != 0:
|
||
if outcount < CallGenBase.ISINSTANCE_CLASS_MAX:
|
||
names[outcount] = sizet(cur)
|
||
outcount += 1
|
||
# 子类入队:遍历全部已注册 struct,ParentNames 含 cur 者
|
||
# 【守卫】这是按序号(0..StructCount-1)的全量遍历,非按名查找,
|
||
# 不走 StructNameIdx 索引:需枚举每个条目的 ParentNames | 按序号
|
||
# 取条目,语义等价于"扫描全表收集子类",不可改为 find_struct。
|
||
scnt: int = self.Gen.StructGen.get_struct_count()
|
||
for i in range(scnt):
|
||
e2: GenTypes.StructEntry* = 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* = (sizet*)(e2.ParentNames)
|
||
for j in range(e2.ParentCount):
|
||
pa: sizet = parr[j]
|
||
if pa != 0:
|
||
pn: str = rawptr(pa)
|
||
if pn is not None and string.strcmp(pn, cur) == 0:
|
||
if qcount < CallGenBase.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*,
|
||
builder: llvmlite.IRBuilder*,
|
||
mod: llvmlite.LLVMModule*,
|
||
class_name: str,
|
||
trans: HT.Translator* = None) -> llvmlite.Value*:
|
||
"""构造类 vtable 地址引用(i8*):本模块已定义直接引用,跨模块声明 external"""
|
||
if class_name is None:
|
||
return None
|
||
i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool)
|
||
i8_ptr_ty: llvmlite.LLVMType* = 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 = rawptr(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* = self.Gen.ExprGenAttr.find_global_in_module(mod, mangled)
|
||
ref_ty: llvmlite.LLVMType* = 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* = 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* = 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*,
|
||
obj_ptr: llvmlite.Value*,
|
||
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* = self.Gen.StructGen.get_mro_chain(pool, sname)
|
||
if mro is not None:
|
||
k: int = 0
|
||
while mro[k] != 0:
|
||
mn: str = rawptr(mro[k])
|
||
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*,
|
||
builder: llvmlite.IRBuilder*,
|
||
mod: llvmlite.LLVMModule*,
|
||
closure_alloca: llvmlite.Value*,
|
||
cargs: list[ast.AST*]*,
|
||
can: sizet,
|
||
trans: HT.Translator* = None) -> llvmlite.Value*:
|
||
"""通过闭包指针间接调用(支持带参 lambda:i32(i8*, args...))"""
|
||
if builder is None or closure_alloca is None:
|
||
return None
|
||
|
||
i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool)
|
||
i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty)
|
||
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
|
||
|
||
# 1. 加载闭包指针 (i8*)
|
||
closure_ptr: llvmlite.Value* = 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* = llvmlite.build_bitcast(builder, closure_ptr, llvmlite.Ptr(pool, i8_ptr_ty))
|
||
if fn_ptr_addr is None:
|
||
return None
|
||
fn_raw: llvmlite.Value* = 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* = llvmlite.const_int32(pool, 8)
|
||
env_addr: llvmlite.Value* = llvmlite.build_gep(builder, i8_ty, closure_ptr, eight_val)
|
||
if env_addr is None:
|
||
return None
|
||
env_ptr: llvmlite.Value* = 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* = env_ptr
|
||
arg_tail: llvmlite.Value* = env_ptr
|
||
param_node: llvmlite.ParamNode* = llvmlite.new_param_node(pool, i8_ptr_ty)
|
||
pn_tail: llvmlite.ParamNode* = param_node
|
||
if can > 0 and cargs is not None and trans is not None:
|
||
for ai in range(can):
|
||
arg: ast.AST* = cargs.get(ai)
|
||
if arg is None: continue
|
||
arg_val: llvmlite.Value* = 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* = 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* = llvmlite.Func(pool, i32_ty, param_node, total_args)
|
||
func_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, func_ty)
|
||
fn_typed: llvmlite.Value* = 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*) -> 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* = alloca.Ty.Pointee
|
||
if pointee is None or self.Gen.ExprGenBase.is_ptr_type(pointee) == 0:
|
||
return 0
|
||
inner: llvmlite.LLVMType* = 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 * CallGenBase.MAX_CLOSURE_NAMES)
|
||
if self.ClosureNames is None: return 0
|
||
string.memset(self.ClosureNames, 0, 64 * CallGenBase.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 >= CallGenBase.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 * CallGenBase.MAX_FUNC_PTR_SIGS)
|
||
self.FuncptrRets = CompilerFactory.factory.PermPool.alloc(8 * CallGenBase.MAX_FUNC_PTR_SIGS)
|
||
if self.FuncptrNames is None or self.FuncptrRets is None:
|
||
return 0
|
||
string.memset(self.FuncptrNames, 0, 64 * CallGenBase.MAX_FUNC_PTR_SIGS)
|
||
return 1
|
||
|
||
|
||
def _func_ptr_sig_fatal(self, pool: memhub.MemBuddy*,
|
||
node: ast.AST*, name: str,
|
||
ret_ty: llvmlite.LLVMType*,
|
||
reason: str) -> None:
|
||
"""函数指针签名登记失败 → 编译期报错(文案含变量名/返回类型/上限/处置建议)
|
||
|
||
原实现满表时静默 return 1:登记被丢弃后,调用点才以
|
||
"函数指针变量 'X' 的返回类型未注册(t.Callable 注解缺失)"
|
||
(下方 _translate_func_ptr_call:843-850)报错,定位到调用行而非登记处,
|
||
掩盖真因(表满/重名冲突)。此处统一在登记点 fail-fast。
|
||
fatal_error 终止编译、不返回,故调用方的返回值分支仅为防御性写法。
|
||
"""
|
||
cap: int = CallGenBase.MAX_FUNC_PTR_SIGS
|
||
ret_str: str = "?"
|
||
if ret_ty is not None:
|
||
typed_buf: str = pool.alloc(96)
|
||
if typed_buf is not None:
|
||
llvmlite.TypePrint(typed_buf, 96, ret_ty, pool)
|
||
if typed_buf[0] != '\0':
|
||
ret_str = typed_buf
|
||
msg_buf: str = pool.alloc(1024)
|
||
if msg_buf is not None:
|
||
viperlib.snprintf(
|
||
msg_buf, 1024,
|
||
"函数指针签名表登记失败:变量 '%s'(返回类型 %s)——%s。"
|
||
"当前上限 MAX_FUNC_PTR_SIGS=%d,已登记 %d 条。"
|
||
"同名同返回类型的重复登记已做原地命中、不占新槽位;"
|
||
"若确实需要更多函数指针变量,请上调 CallGenBase.vp 的 "
|
||
"MAX_FUNC_PTR_SIGS(全仓唯一来源,改此一处即全仓生效)",
|
||
name, ret_str, reason, cap, self.FuncptrCount)
|
||
self.Gen.TypeGenErr.fatal_error(node, msg_buf, "TypeError")
|
||
return
|
||
self.Gen.TypeGenErr.fatal_error(node, "函数指针签名表登记失败(签名表已满或变量名冲突)", "TypeError")
|
||
|
||
def register_func_ptr_sig(self, pool: memhub.MemBuddy*, name: str,
|
||
ret_ty: llvmlite.LLVMType*,
|
||
node: ast.AST* = None) -> int:
|
||
"""注册函数指针变量的返回类型签名,0=成功(含幂等命中)/ 1=失败(已报错终止)
|
||
|
||
表按**裸变量名**全局共享(PermPool,跨文件/跨阶段存活),同一变量可能被
|
||
多轮登记(模块级:Translator.vp:568-575 的预注册遍与 translate_children
|
||
TranslatorGenMixin.vp:130-136 各见同一 AnnAssign 一次):
|
||
* 同名同返回类型 → 原地命中、不新增槽位(否则重复登记把表撑爆);
|
||
* 同名不同返回类型 → 报错。既不能静默丢弃(查找返回先登记值:先翻译
|
||
模块已按旧值生成间接调用,后登记模块却按新值,同一名字两种 ABI),
|
||
也不能静默覆盖(先翻译模块的调用点已按旧值生成)——两者都是无声误编译;
|
||
* 满表 → 报错(原实现静默丢弃)。
|
||
"""
|
||
if name is None or ret_ty is None:
|
||
return 1
|
||
if self._ensure_funcptr_sigs() == 0:
|
||
self._func_ptr_sig_fatal(pool, node, name, ret_ty,
|
||
"签名表分配失败(PermPool 内存不足)")
|
||
return 1
|
||
# 幂等/冲突检查:线性扫已登记裸名(FuncptrCount 上限 64,代价可忽略)
|
||
i: sizet
|
||
for i in range(self.FuncptrCount):
|
||
idx_hit: sizet = sizet(i) * 64
|
||
if string.strcmp(self.FuncptrNames + idx_hit, name) == 0:
|
||
prev_ret: llvmlite.LLVMType* = (llvmlite.LLVMType*)(self.FuncptrRets[i])
|
||
if prev_ret is not None and self.Gen.AssignGen._stg_ty_equal(pool, prev_ret, ret_ty) != 0:
|
||
return 0
|
||
self._func_ptr_sig_fatal(pool, node, name, ret_ty, "该名字已按另一种返回类型登记过")
|
||
return 1
|
||
if self.FuncptrCount >= CallGenBase.MAX_FUNC_PTR_SIGS:
|
||
self._func_ptr_sig_fatal(pool, node, name, ret_ty, "签名表已满")
|
||
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* = 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*:
|
||
"""查函数指针变量的返回类型,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*)(self.FuncptrRets[i])
|
||
return None
|
||
|
||
|
||
def _translate_func_ptr_call(self, pool: memhub.MemBuddy*,
|
||
builder: llvmlite.IRBuilder*,
|
||
mod: llvmlite.LLVMModule*,
|
||
fp_alloca: llvmlite.Value*,
|
||
func_name: str,
|
||
cargs: list[ast.AST*]*,
|
||
can: sizet,
|
||
trans: HT.Translator*) -> llvmlite.Value*:
|
||
"""函数指针变量间接调用,返回结果 Value"""
|
||
if builder is None or fp_alloca is None:
|
||
return None
|
||
i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool)
|
||
i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty)
|
||
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
|
||
|
||
# 1. load 函数地址 (i8*)
|
||
fn_i8: llvmlite.Value* = llvmlite.build_load(builder, i8_ptr_ty, fp_alloca)
|
||
if fn_i8 is None: return None
|
||
|
||
# 2. 翻译实参并链接为 Value 链表
|
||
head: llvmlite.Value* = None
|
||
tail: llvmlite.Value* = None
|
||
arg_count: int = 0
|
||
ai: sizet
|
||
for ai in range(can):
|
||
arg: ast.AST* = cargs.get(ai)
|
||
if arg is not None:
|
||
arg_val: llvmlite.Value* = 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* = 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* = None
|
||
fp_prev: llvmlite.ParamNode* = None
|
||
cur_v: llvmlite.Value* = head
|
||
for pi in range(arg_count):
|
||
if cur_v is None:
|
||
break
|
||
cur_ty: llvmlite.LLVMType* = llvmlite.value_get_ty(cur_v)
|
||
pn2: llvmlite.ParamNode* = 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* = llvmlite.Func(pool, ret_ty, fp_first, arg_count)
|
||
if func_ty is None:
|
||
return None
|
||
func_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, func_ty)
|
||
|
||
# 4. bitcast i8* → 函数指针类型,间接调用
|
||
fn_typed: llvmlite.Value* = 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*,
|
||
builder: llvmlite.IRBuilder*,
|
||
mod: llvmlite.LLVMModule*,
|
||
cl: ast.Call*,
|
||
trans: HT.Translator* = None) -> None:
|
||
"""翻译 printf 调用(特殊处理格式字符串)"""
|
||
cargs: list[ast.AST*]* = cl.args
|
||
if cargs is None: return
|
||
can: sizet = len(cargs)
|
||
if can == 0: return
|
||
|
||
arg0: ast.AST* = 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* = ast.Constant*(arg0)
|
||
if cn.const_kind == ast.CONST_STR:
|
||
fmt_str = cn.str_val
|
||
|
||
if fmt_str is None: return
|
||
|
||
fmt_ptr: llvmlite.Value* = self.Gen.ExprGenConst.create_global_string(builder, pool, mod, fmt_str, trans)
|
||
if fmt_ptr is None: return
|
||
|
||
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
|
||
|
||
# 翻译额外参数并链接
|
||
prev: llvmlite.Value* = fmt_ptr
|
||
for ai in range(1, can):
|
||
arg: ast.AST* = cargs.get(ai)
|
||
if arg is not None:
|
||
arg_val: llvmlite.Value* = 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* = 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*,
|
||
builder: llvmlite.IRBuilder*,
|
||
mod: llvmlite.LLVMModule*,
|
||
cl: ast.Call*,
|
||
trans: HT.Translator* = None) -> None:
|
||
"""翻译 print 调用(类型感知格式化 + 默认换行)"""
|
||
cargs: list[ast.AST*]* = 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* = llvmlite.Int32(pool)
|
||
i64_ty: llvmlite.LLVMType* = llvmlite.Int64(pool)
|
||
dbl_ty: llvmlite.LLVMType* = llvmlite.Double(pool)
|
||
|
||
can: sizet = len(cargs)
|
||
arg_head: llvmlite.Value* = None
|
||
arg_tail: llvmlite.Value* = None
|
||
arg_count: int = 1 # 格式串本身是第 1 个 printf 参数
|
||
|
||
for ai in range(can):
|
||
arg: ast.AST* = cargs.get(ai)
|
||
if arg is None: continue
|
||
arg_val: llvmlite.Value* = 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* = None
|
||
array_elem_bits: int = 0
|
||
if arg.kind() == ast.ASTKind.Name and trans is not None:
|
||
anm: ast.Name* = ast.Name*(arg)
|
||
if anm.id is not None:
|
||
arr_alloca: llvmlite.Value* = 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* = 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* = 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* = 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* = 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*, max_count: int) -> GenTypes.FuncEntry*:
|
||
"""分配并清零函数表数组"""
|
||
size: sizet = max_count * GenTypes.FuncEntry.__sizeof__()
|
||
funcs_ptr: GenTypes.FuncEntry* = 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*,
|
||
func_count: int,
|
||
name: str,
|
||
owner_sha1: str = None) -> llvmlite.Function*:
|
||
"""在函数表中按名称查找,返回 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(find_func_global / _register_global_func 去重路径):
|
||
# owner 分支不激活 ⇒ 等价于"首个同名条目的 Func"(含 Func 为 None → None),
|
||
# 走名索引快速路径。funcs 非全局表(逐文件 _funcs)或带 owner 时保持下方
|
||
# 线性扫描(owner 优先需按同组顺序遍历,索引不适用)。
|
||
gfuncs_match: int = 0
|
||
if owner_sha1 is None and self.GlobalFuncs is not None:
|
||
if uint64(funcs) == uint64(self.GlobalFuncs) and func_count == self.GlobalFuncCount:
|
||
gfuncs_match = 1
|
||
if gfuncs_match != 0 and self.GlobalFuncNameIdxBuilt == self.GlobalFuncCount \
|
||
and self.GlobalFuncNameIdx is not None and self.GlobalFuncNameIdxCap > 0:
|
||
fi_t: int = _gfn_idx_find(self.GlobalFuncs, self.GlobalFuncNameIdx,
|
||
self.GlobalFuncNameIdxCap, name)
|
||
if fi_t >= 0:
|
||
fe_t: GenTypes.FuncEntry* = GenTypes.FuncEntry*((uint64(self.GlobalFuncs) + fi_t * entry_size))
|
||
if fe_t is not None:
|
||
return fe_t.Func
|
||
# 索引可信(Built==GlobalFuncCount | 查询名非空)⇒ 未命中即"确无同名条目":
|
||
# 全局表只经 _register_global_func 追加(每次追加即同步索引,失败则置
|
||
# Built=-1),名注册后不再改写 ⇒ owner_sha1 为 None 时原线性扫描等价于
|
||
# "首个同名条目的 Func",未命中必为 None。索引不可信时回退下方线性扫描。
|
||
return None
|
||
# 单遍扫描(合并原 owner 优先遍 + 通用遍,语义完全一致但省一半遍历):扫描中同时记录"首个同裸名条目"作通用兜底;一旦发现本模块条目(mangled 名以 "{owner_sha1}." 开头,16 位前缀 + '.')立即返回
|
||
fallback_entry: GenTypes.FuncEntry* = None
|
||
for i in range(func_count):
|
||
entry_addr: uint64 = uint64(funcs) + i * entry_size
|
||
entry: GenTypes.FuncEntry* = GenTypes.FuncEntry*(entry_addr)
|
||
if entry is not None and entry.Name is not None:
|
||
# 快速路径:同名要求首字符相等(strcmp 判等蕴含首字符相等),
|
||
# 首字符不同者直接跳过 strcmp,避免全表每槽一次函数调用。
|
||
if entry.Name[0] == name[0] and 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*,
|
||
func_count: int,
|
||
name: str,
|
||
func: llvmlite.Function*,
|
||
max_count: int,
|
||
defaults: t.CPtr = None,
|
||
default_count: int = 0,
|
||
param_count: int = 0,
|
||
pool: memhub.MemBuddy* = 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* = GenTypes.FuncEntry*(entry_addr)
|
||
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 = CallGenBase.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
|
||
# 名索引(PermPool,与表同生命周期)。分配失败 → 保持不可信(Built=-1),
|
||
# 查找/去重一律回退线性扫描(语义完全一致,不因此使初始化失败)。
|
||
idx_bytes: sizet = sizet(GLOBAL_FUNC_IDX_CAP) * 8
|
||
idx_buf: sizet* = CompilerFactory.factory.PermPool.alloc(idx_bytes)
|
||
if idx_buf is None:
|
||
self.GlobalFuncNameIdx = None
|
||
self.GlobalFuncNameIdxCap = 0
|
||
self.GlobalFuncNameIdxBuilt = -1
|
||
else:
|
||
string.memset(idx_buf, 0, idx_bytes)
|
||
self.GlobalFuncNameIdx = idx_buf
|
||
self.GlobalFuncNameIdxCap = GLOBAL_FUNC_IDX_CAP
|
||
self.GlobalFuncNameIdxBuilt = 0
|
||
return 1
|
||
|
||
|
||
def _register_global_func(self, name: str, func: llvmlite.Function*,
|
||
pool: memhub.MemBuddy* = 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 >= CallGenBase.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* = GenTypes.FuncEntry*(entry_addr)
|
||
# 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
|
||
# 同步名索引(槽下标 = 新条目下标):仅当插入前可信(Built==Count-1)
|
||
# 且插入成功;否则标记不可信(查找回退线性扫描)。
|
||
if self.GlobalFuncNameIdxBuilt == self.GlobalFuncCount - 1 \
|
||
and _gfn_idx_insert(self.GlobalFuncNameIdx, self.GlobalFuncNameIdxCap,
|
||
self.GlobalFuncCount - 1, name_copy) == 0:
|
||
self.GlobalFuncNameIdxBuilt = self.GlobalFuncCount
|
||
else:
|
||
self.GlobalFuncNameIdxBuilt = -1
|
||
return 0
|
||
|
||
|
||
def update_global_func_spec(self, name: str,
|
||
func: llvmlite.Function*) -> 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* = 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 完成后调用。参数沿 function_get_param_head 的 Param 链表两遍遍历(先计数再填充,llvmlite 无按下标取参且无法预知长度)。与 TSpec.SpecFromLLVMType 的 Func 分支不同:后者不含变参信息(恒置 IsVarArg=0),故此处直接用 NewTypeFunc(..., func.IsVarArg)。失败返回 None,调用方保留 None 不造伪 spec
|
||
def _build_func_spec(self, func: llvmlite.Function*) -> TSpec.TypeSpec*:
|
||
"""由函数对象构造整签名 TypeSpec,失败返回 None"""
|
||
if func is None: return None
|
||
arena: TSpec.TypeSpecArena* = self.Gen.TypeGenBase.ensure_spec_arena()
|
||
if arena is None: return None
|
||
ret_s: TSpec.TypeSpec* = TSpec.SpecFromLLVMType(arena, llvmlite.function_get_ret_ty(func))
|
||
if ret_s is None: return None
|
||
# 第一遍:计数
|
||
cnt: int = 0
|
||
cur: llvmlite.Param* = 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* = 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* = TSpec.SpecFromLLVMType(arena, llvmlite.param_get_ty(cur))
|
||
if ps is None: return None
|
||
slot: sizet* = (sizet*)(uint64(params_arr) + uint64(i * 8))
|
||
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*:
|
||
"""在全局函数表中按名称查找,返回 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*:
|
||
"""在全局函数表中按名称查找,返回完整 FuncEntry(含 Spec)或 None"""
|
||
if name is None or self.GlobalFuncs is None: return None
|
||
entry_size: sizet = GenTypes.FuncEntry.__sizeof__()
|
||
# 名索引快速路径:可信(Built==Count)时一次探测返回首个同名条目
|
||
# (= 原线性扫描首个命中);可信且查询名非空时未命中即"确无同名条目"
|
||
# (全局表只经 _register_global_func 追加并同步索引,名注册后不再改写),
|
||
# 直接返回 None;索引不可信 → 回退下方原线性扫描。
|
||
if self.GlobalFuncNameIdxBuilt == self.GlobalFuncCount and self.GlobalFuncNameIdx is not None and self.GlobalFuncNameIdxCap > 0:
|
||
gi: int = _gfn_idx_find(self.GlobalFuncs, self.GlobalFuncNameIdx, self.GlobalFuncNameIdxCap, name)
|
||
if gi >= 0:
|
||
entry_g: GenTypes.FuncEntry* = GenTypes.FuncEntry*(uint64(self.GlobalFuncs) + gi * entry_size)
|
||
return entry_g
|
||
return None
|
||
for i in range(self.GlobalFuncCount):
|
||
entry_addr: uint64 = uint64(self.GlobalFuncs) + i * entry_size
|
||
entry: GenTypes.FuncEntry* = GenTypes.FuncEntry*(entry_addr)
|
||
if entry.Name is not None:
|
||
# 快速路径:同名要求首字符相等(strcmp 判等蕴含首字符相等),
|
||
# 首字符不同者直接跳过 strcmp。
|
||
if entry.Name[0] == name[0] and 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 = CallGenBase.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 >= CallGenBase.GLOBAL_DEFAULTS_MAX: return 1
|
||
entry_size: sizet = GenTypes.FuncDefaultsEntry.__sizeof__()
|
||
entry_addr: uint64 = uint64(self.GlobalDefaults) + self.GlobalDefaultsCount * entry_size
|
||
entry: GenTypes.FuncDefaultsEntry* = GenTypes.FuncDefaultsEntry*(entry_addr)
|
||
# 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* = 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*]* = (list[ast.AST*] | t.CPtr)(uint64(defaults))
|
||
di: int
|
||
for di in range(default_count):
|
||
dnode: ast.AST* = dl.get(di)
|
||
if dnode is not None and dnode.kind() == ast.ASTKind.Constant:
|
||
dcn: ast.Constant* = ast.Constant*(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* = ast.Name*(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* = ast.UnaryOp*(dnode)
|
||
if du.operand is not None and du.operand.kind() == ast.ASTKind.Constant:
|
||
doc: ast.Constant* = ast.Constant*(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*:
|
||
"""按函数名(可选按定义模块 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* = GenTypes.FuncDefaultsEntry*(entry_addr)
|
||
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*,
|
||
mod: llvmlite.LLVMModule*,
|
||
gd_entry: GenTypes.FuncDefaultsEntry*,
|
||
di: int,
|
||
trans: HT.Translator*,
|
||
builder: llvmlite.IRBuilder*) -> llvmlite.Value*:
|
||
"""从快照重建第 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* = llvmlite.Int8(pool)
|
||
i8_ptr_ty: llvmlite.LLVMType* = 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 = rawptr(gd_entry.ConstStrs[di])
|
||
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*,
|
||
func_count: int,
|
||
name: str) -> GenTypes.FuncEntry*:
|
||
"""在函数表中按名称查找,返回完整 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* = GenTypes.FuncEntry*(entry_addr)
|
||
if entry.Name is not None:
|
||
# 快速路径:strcmp 判等蕴含首字符相等,首字符不同者跳过 strcmp
|
||
if entry.Name[0] == name[0] and string.strcmp(entry.Name, name) == 0:
|
||
return entry
|
||
return None
|
||
|
||
def find_func_entry_in_table_owned(self, funcs: GenTypes.FuncEntry*,
|
||
func_count: int,
|
||
name: str,
|
||
owner_sha1: str) -> GenTypes.FuncEntry*:
|
||
"""按「裸名 + 定义模块 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* = GenTypes.FuncEntry*(entry_addr)
|
||
if entry is None or entry.Name is None:
|
||
continue
|
||
# 快速路径:strcmp 判等要求首字符相等,首字符不同者跳过 strcmp
|
||
# (热点:本函数对函数表逐条按裸名 + 定义模块 SHA1 比对)。
|
||
if entry.Name[0] != name[0] or 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*, trans: HT.Translator*) -> ExprCallHandle*:
|
||
h: ExprCallHandle* = 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 等。
|
||
# ============================================================
|
||
novirtual class ExprCallHandle(HT.Mixin):
|
||
"""函数调用处理器:继承 Mixin 获得 Trans 回指针"""
|
||
|
||
def __init__(self, trans: HT.Translator*):
|
||
self.Trans = trans
|
||
|
||
# ============================================================
|
||
# HandleCall - 翻译函数调用,返回 call 结果 Value
|
||
# ============================================================
|
||
def HandleCall(self, node: ast.AST*) -> llvmlite.Value*:
|
||
"""翻译函数调用,从 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*):
|
||
"""翻译 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*):
|
||
"""翻译 print 调用(类型感知格式化 + 默认换行)"""
|
||
GenApi.translate_print_call(self.Trans.Pool, self.Trans._cur_builder, self.Trans.Module, cl, self.Trans)
|
||
|