feat: 支持 t.Callable 函数指针类型注解、赋值与间接调用(含返回类型签名缓存)
This commit is contained in:
1 parent
3197152d4e
commit
09833a80eb
3 files changed
+212
-10
No files matched your search
@@ -5394,11 +5394,16 @@ def translate_call(pool: memhub.MemBuddy | t.CPtr,
|
||||
else:
|
||||
call_ret_ty = _infer_external_func_ret_ty(pool, func_name)
|
||||
|
||||
# 如果模块中找不到函数,检查是否是变量(闭包调用)
|
||||
# 如果模块中找不到函数,检查是否是变量(函数指针 / 闭包调用)
|
||||
if found_func is None:
|
||||
closure_ptr: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, func_name)
|
||||
if closure_ptr is not None:
|
||||
return translate_closure_call(pool, builder, mod, closure_ptr,
|
||||
fp_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, func_name)
|
||||
if fp_alloca is not None:
|
||||
# 函数指针变量(t.Callable 注解 → i8** alloca):按实参构造签名间接调用
|
||||
if _is_func_ptr_alloca(fp_alloca) != 0:
|
||||
return _translate_func_ptr_call(pool, builder, mod, fp_alloca,
|
||||
func_name, cargs, can, trans)
|
||||
# 闭包变量(i8* alloca):走闭包调用路径
|
||||
return translate_closure_call(pool, builder, mod, fp_alloca,
|
||||
cargs, can)
|
||||
|
||||
# 翻译参数并链接
|
||||
@@ -5756,6 +5761,159 @@ def translate_closure_call(pool: memhub.MemBuddy | t.CPtr,
|
||||
env_ptr.Next = None
|
||||
return llvmlite.build_call_indirect(builder, fn_typed, env_ptr, 1, i32_ty)
|
||||
|
||||
# ============================================================
|
||||
# _is_func_ptr_alloca - 判断变量 alloca 是否为函数指针变量
|
||||
#
|
||||
# 函数指针变量(t.Callable 注解 → i8*)的 alloca 类型是 Ptr(Ptr(i8)) = i8**;
|
||||
# 闭包变量 alloca 是 i8*(Ptr(i8))。通过类型层级区分。
|
||||
# ============================================================
|
||||
def _is_func_ptr_alloca(alloca: llvmlite.Value | t.CPtr) -> int:
|
||||
"""判断 alloca 是否为函数指针变量(类型 Ptr(Ptr(i8))),1=是 / 0=否"""
|
||||
if alloca is None or alloca.Ty is None:
|
||||
return 0
|
||||
if HandlesExpr.is_ptr_type(alloca.Ty) == 0:
|
||||
return 0
|
||||
pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee
|
||||
if pointee is None or HandlesExpr.is_ptr_type(pointee) == 0:
|
||||
return 0
|
||||
inner: llvmlite.LLVMType | t.CPtr = pointee.Pointee
|
||||
if inner is None or HandlesExpr.is_ptr_type(inner) != 0:
|
||||
return 0
|
||||
return 1
|
||||
|
||||
# ============================================================
|
||||
# 函数指针变量签名表(变量名 → 返回类型)
|
||||
#
|
||||
# AnnAssign 处理 t.Callable 注解时注册,函数指针间接调用时
|
||||
# 按注册的返回类型构造签名(而非默认 i32)。
|
||||
# ============================================================
|
||||
MAX_FUNC_PTR_SIGS: t.CDefine = 64
|
||||
_g_funcptr_names: t.CChar | t.CPtr = None
|
||||
_g_funcptr_rets: t.CUInt64T | t.CPtr = None
|
||||
_g_funcptr_count: int = 0
|
||||
|
||||
|
||||
def _ensure_funcptr_sigs() -> int:
|
||||
"""确保函数指针签名表已分配(stdlib.malloc,懒初始化)"""
|
||||
global _g_funcptr_names, _g_funcptr_rets
|
||||
if _g_funcptr_names is not None:
|
||||
return 1
|
||||
_g_funcptr_names = stdlib.malloc(64 * MAX_FUNC_PTR_SIGS)
|
||||
_g_funcptr_rets = stdlib.malloc(8 * MAX_FUNC_PTR_SIGS)
|
||||
if _g_funcptr_names is None or _g_funcptr_rets is None:
|
||||
return 0
|
||||
string.memset(_g_funcptr_names, 0, 64 * MAX_FUNC_PTR_SIGS)
|
||||
return 1
|
||||
|
||||
|
||||
def register_func_ptr_sig(name: str,
|
||||
ret_ty: llvmlite.LLVMType | t.CPtr) -> int:
|
||||
"""注册函数指针变量的返回类型签名,0 成功"""
|
||||
global _g_funcptr_count
|
||||
if name is None or ret_ty is None:
|
||||
return 1
|
||||
if _ensure_funcptr_sigs() == 0:
|
||||
return 1
|
||||
if _g_funcptr_count >= MAX_FUNC_PTR_SIGS:
|
||||
return 1
|
||||
idx: t.CSizeT = t.CSizeT(_g_funcptr_count) * 64
|
||||
string.strcpy(_g_funcptr_names + idx, name)
|
||||
_g_funcptr_rets[_g_funcptr_count] = t.CUInt64T(ret_ty)
|
||||
_g_funcptr_count += 1
|
||||
return 0
|
||||
|
||||
|
||||
def lookup_func_ptr_ret(name: str) -> llvmlite.LLVMType | t.CPtr:
|
||||
"""查函数指针变量的返回类型,None=未注册(调用时默认 i32)"""
|
||||
if name is None or _g_funcptr_names is None:
|
||||
return None
|
||||
for i in range(_g_funcptr_count):
|
||||
idx: t.CSizeT = t.CSizeT(i) * 64
|
||||
if string.strcmp(_g_funcptr_names + idx, name) == 0:
|
||||
return (llvmlite.LLVMType | t.CPtr)(
|
||||
t.CVoid(_g_funcptr_rets[i], t.CPtr))
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _translate_func_ptr_call - 函数指针变量间接调用
|
||||
#
|
||||
# func_p: t.Callable[[A, B], Ret] 后调用 func_p(a, b):
|
||||
# 1. load 函数地址 (i8*)
|
||||
# 2. 翻译实参并链接为 Value 链表
|
||||
# 3. 按实参类型 + 注册的返回类型构造签名(未注册时默认 i32)
|
||||
# 4. bitcast i8* → 函数指针类型,间接调用
|
||||
# ============================================================
|
||||
def _translate_func_ptr_call(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: t.CSizeT,
|
||||
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: t.CSizeT
|
||||
for ai in range(can):
|
||||
arg: ast.AST | t.CPtr = cargs.get(ai)
|
||||
if arg is not None:
|
||||
arg_val: llvmlite.Value | t.CPtr = HandlesExpr.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. 按实参类型 + 注册的返回类型构造签名(未注册返回类型时默认 i32)
|
||||
ret_ty: llvmlite.LLVMType | t.CPtr = lookup_func_ptr_ret(func_name)
|
||||
if ret_ty is None:
|
||||
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)
|
||||
|
||||
# ============================================================
|
||||
# 翻译 printf 调用 — 模块级版本
|
||||
# ============================================================
|
||||
|
||||
Reference in new issue
Block a user