Files
ViperC/App/lib/core/Gen/Func/FuncGenDef.vp
T
TermiNexus 2f6db41b11 fix(void): 形参与字段注解禁止 void,改为编译期 fail-fast
void 只允许用于 void* 与 typedef 不透明结构体别名(用户 2026-10-01 定)。
此前 def f(p: void) / class C: x: void 不走 translate_annassign,会按 LLVM void
直接建形参/字段槽,生成非法 IR 拖到 llc 阶段才暴露。现补 6 处形参落点
(FuncGenDef 前向声明/外部声明/函数体/alloca 各一、ClassGenVTable 签名/alloca 各一)
与 1 处字段落点(ClassGenDef),统一编译期 TypeError。
void* 已在上游归并为 i8*,不受影响。
2026-10-01 21:43:11 +08:00

1388 lines
88 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import lib.core.Gen.GenTypes as GenTypes
import lib.core.Gen.Func.FuncGenMixin as FuncGenMixin
import t, c
from stdint import *
import ast
import llvmlite
import memhub
import string
import viperlib
import stdio
import stdlib
import lib.core.VLogger as VLogger
import lib.core.Gen.Translator as HT
import lib.core.Gen.Call.CallGenBase as CallGenBase
import lib.core.Gen.GenApi as GenApi
import lib.core.Gen.DebugInfoGen as DebugInfoGen
# ============================================================
# FuncGenDef - 函数声明 / translate_function_def / decorator wrapper
# ============================================================
novirtual class FuncGenDef(CallGenBase.CallGenBase):
"""函数声明 / translate_function_def / decorator wrapper"""
# forward_declare_functions - 预扫描所有顶层 FunctionDef,创建前向声明
# 解决同模块内前向引用问题(如 sprintf 调用定义在后面的 vsnprintf)。
# 对每个顶层 FunctionDef: 1) 推断返回/参数类型 2) 计算 mangled name(含 SHA1 前缀)
# 3) 创建 declare(IsDeclared=1) 4) 添加参数 5) 注册到函数表。
# 后续 translate_function_def 经 find_func_in_module 复用该 declare(清除 IsDeclared,
# 跳过参数创建,直接添加函数体)。
def forward_declare_functions(self, trans: HT.Translator*,
tree: ast.AST*) -> int:
"""预扫描所有顶层 FunctionDef,创建前向声明"""
if trans is None or tree is None: return 0
pool: memhub.MemBuddy* = trans.Pool
mod: llvmlite.LLVMModule* = trans.Module
if pool is None or mod is None: return 0
imported_modules: str = trans._imported_modules
from_imports: str = trans._from_imports
funcs_ptr: GenTypes.FuncEntry* = trans._funcs
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty)
ch: list[ast.AST*]* = tree.children
if ch is None: return 0
# 解析函数签名期间临时切换到"仅声明"模式:
# 签名里的泛型类注解(如 _empty_like(a: ndarray[t.CDouble]))会触发泛型特化,
# 若此时特化立即翻译方法体,方法体前向引用同模块后续函数(如 _empty_like 自身)
# 会因 declare 尚未创建而报"裸名调用未定义且未导入"。
# 临时 declare_only=1 使特化只注册结构体(mark_only 不译方法体),
# 方法体由后续 resolve_annotation_type 命中已注册结构体时补译
# (_specialize_generic_class 的 Phase B 补译分支)。
saved_declare_only: int = trans._declare_only
trans._declare_only = 1
cn_count: sizet = len(ch)
# ============================================================
# 预注册当前模块 ClassDef(declare_only 模式,仅 struct+字段+方法声明,
# 不译方法体)。背景:1a 阶段(declare_only=1)不注入 vpi、不处理
# import,依赖模块的 CTypedef(stdint 的 u16/u32/UINT 等)查表失败,
# 含此类字段的类(socket.vp SocketAddr: u16/u32/u64)1a 注册整体中止;
# 1b 此处 vpi 注入已完成、typedef 可解析,若不预注册,forward_declare
# 解析返回/参数注解(如 _MakeAddr -> SocketAddr)时类未注册 →
# "函数返回类型解析失败:注解不可解析"(WebTest socket.vp 根因)。
# 按 AST 序预注册保证同文件类间依赖(class A 引用 class B,B 在后)
# 也能先注册。已完整注册的类(1a 成功 / 依赖方 stub 注入含字段)跳过,
# 交由 translate_children 走 existing 路径,无重复处理副作用。
pre_i: sizet
for pre_i in range(cn_count):
pre_child: ast.AST* = ch.get(pre_i)
if pre_child is None: continue
if pre_child.kind() != ast.ASTKind.ClassDef: continue
pre_cd: ast.ClassDef* = ast.ClassDef*(pre_child)
if pre_cd is None or pre_cd.name is None: continue
pre_ex: GenTypes.StructEntry* = self.Gen.StructGen.find_struct_by_module(pre_cd.name, trans.ModuleSha1)
if pre_ex is not None and pre_ex.FieldCount > 0: continue
self.Gen.ClassGenDef.translate_class_def(trans, pre_child)
for ci in range(cn_count):
child: ast.AST* = ch.get(ci)
if child is None: continue
if child.kind() != ast.ASTKind.FunctionDef: continue
fd: ast.FunctionDef* = ast.FunctionDef*(child)
if fd is None or fd.name is None: continue
# PEP 695 泛型函数(def f[T](...) -> T)按普通函数编译(TPV 无泛型
# 函数特化机制,与 translate_function_def L678-691 一致):此处先设置
# 类型参数上下文(T→"int"),使返回/参数注解中的 T 可解析,否则
# forward_declare 阶段 "函数返回类型解析失败:注解不可解析"
# (ExpandKeywordsTest fn ident[T] 根因)。所有退出路径(continue /
# 循环末尾)必须 clear_generic_context,避免污染后续函数注解解析。
tp_names_fd: list[str]* = None
if fd.type_params is not None:
tp_names_fd = fd.type_params
tp_args_fd: list[str]* = list[str](pool, 8)
if tp_args_fd is not None:
tpn_fd: sizet = len(fd.type_params)
tpi_fd: sizet = 0
for tpi_fd in range(tpn_fd):
tp_args_fd.append("int")
self.Gen.TypeGenBase.set_generic_context(tp_names_fd, tp_args_fd)
# 推断返回类型
ret_ty: llvmlite.LLVMType* = None
if fd.returns is not None:
ret_ty = self.Gen.TypeGenResolve.resolve_annotation_type(pool, fd.returns, imported_modules, from_imports, trans, 0)
# 单独 t.CExport 返回注解(def free(...) -> t.CExport:)=
# 导出修饰符,无实际返回类型 → Void(根因:CExport 被 map_t_type
# 回退为 i32 → 掉尾检查强制 return i32,mm.vp free 根因)。
# CExport 混用实际类型(-> t.CExport | int)时保持解析结果。
if fd.returns.kind() == ast.ASTKind.Attribute:
ce_at: ast.Attribute* = ast.Attribute*(fd.returns)
if ce_at.attr is not None and string.strcmp(ce_at.attr, "CExport") == 0:
if ce_at.value is not None and ce_at.value.kind() == ast.ASTKind.Name:
ce_nm: ast.Name* = ast.Name*(ce_at.value)
if ce_nm.id is not None and string.strcmp(ce_nm.id, "t") == 0:
ret_ty = llvmlite.Void(pool)
if ret_ty is None and fd.returns is not None:
if self.Gen.TypeGenErr.has_decorator_marker(fd.returns, "State", 0) != 0:
ret_ty = llvmlite.Void(pool)
# @c.CReturn 装饰器已移除:遇到即编译期报错(多返回值改用 -> tuple[...])
if ret_ty is None:
self.Gen.FuncGenBase.RejectCReturnDecorator(fd, fd.decorator_list)
if ret_ty is None and fd.returns is not None:
# 有返回注解但解析失败:编译期报错,不静默回退 i32。
# (i32 回退曾导致掉尾检查强制 return i32 / 跨模块调用返回类型错位,
# mm.vp free / GetMemoryStats 根因。)无返回注解函数(def foo():)
# 保留 i32 默认,不在此报错。
self.Gen.TypeGenErr.fatal_error(fd, "函数返回类型解析失败:注解不可解析", "TypeError")
return 0
if ret_ty is None:
ret_ty = i32_ty
# 检测 CExtern/State/CExport
has_extern: int = 0
has_state: int = 0
has_export: int = 0
if fd.returns is not None:
has_extern = self.Gen.TypeGenErr.has_decorator_marker(fd.returns, "CExtern", 0)
has_state = self.Gen.TypeGenErr.has_decorator_marker(fd.returns, "State", 0)
has_export = self.Gen.TypeGenErr.has_decorator_marker(fd.returns, "CExport", 0)
# 装饰器形式存储类标记(@t.CExport/@t.CExtern/@t.State/@t.CStatic)
# 对齐 TPC HandlesFunctions._extract_decorator_storage_flags;
# CExport/CExtern/State 影响函数名(导出裸名),CStatic 不影响函数名,
# 但登记到 static 符号表(禁止跨模块使用,见下方 RegisterStaticSymbol)。
# 注意: 用 HandlesClassDef._has_decorator 委托而非 self._has_decorator
# (Mixin 是 @t.NoVTable 静态绑定,跨 Mixin 方法经 MRO 调用会生成
# 不存在的 FuncGenMixin._has_decorator → 链接 undefined symbol)
if fd.decorator_list is not None:
if has_extern == 0 and self.Gen.ClassGenBase._has_decorator(fd.decorator_list, "CExtern") == 1:
has_extern = 1
if has_state == 0 and self.Gen.ClassGenBase._has_decorator(fd.decorator_list, "State") == 1:
has_state = 1
if has_export == 0 and self.Gen.ClassGenBase._has_decorator(fd.decorator_list, "CExport") == 1:
has_export = 1
is_extern_decl: int = 0
if has_extern != 0 or has_state != 0:
is_extern_decl = 1
# static(禁止跨模块使用):注解形态(`def f() -> t.CVoid | t.CStatic:`)
# 与装饰器形态(`@t.CStatic`;裸 `static def f(...)` 已由解析层归一为
# 装饰器)同源识别并登记。逻辑收敛在 _RegisterStaticFunc 内(不内联——
# 本函数含多分支,内联新增分支会干扰其类型推断,与 ExprGenAttr /
# CallGenMixin / TranslatorGenMixin 同款处理)。
self._RegisterStaticFunc(trans, fd)
# 计算 mangled name
if has_extern != 0 or has_state != 0 or has_export != 0 or string.strcmp(fd.name, "main") == 0:
mangled_name: str = fd.name
else:
mangled_name = self.Gen.FuncGenBase._mangle_func_name(trans, fd.name, 0)
# 如果函数已存在(如重复定义),跳过
existing: llvmlite.Function* = self.Gen.CallGenBase.find_func_in_module(mod, mangled_name)
if existing is not None:
if tp_names_fd is not None:
self.Gen.TypeGenBase.clear_generic_context()
continue
# 创建 declare
func: llvmlite.Function* = llvmlite.create_declare(pool, mod, mangled_name, ret_ty)
if func is None:
if tp_names_fd is not None:
self.Gen.TypeGenBase.clear_generic_context()
continue
# 提取默认参数信息
# 注意: 必须先把属性赋给显式类型为 list[...] | t.CPtr 的局部变量再调用 __len__(),
# 否则编译器无法识别属性返回的 list 类型,GEP base 会变成 i32 0 导致 llc 报错
fd_args_node: ast.Arguments* = fd.args
fd_defaults: t.CPtr = None
fd_default_count: int = 0
fd_param_count: int = 0
if fd_args_node is not None:
fd_ags: ast.Arguments* = ast.Arguments*(fd_args_node)
if fd_ags.args is not None:
fd_alist: list[ast.AST*]* = fd_ags.args
fd_param_count = len(fd_alist)
if fd_ags.defaults is not None:
fd_dlist: list[ast.AST*]* = fd_ags.defaults
fd_defaults = fd_dlist
fd_default_count = len(fd_dlist)
# 注册到函数表(用裸名 fd.name,不是 mangled_name)
max_funcs: int = 1024
cur_count: int = trans._func_count
if self.Gen.CallGenLeafKit.add_func_to_table(funcs_ptr, cur_count, fd.name, func, max_funcs,
fd_defaults, fd_default_count, fd_param_count,
trans.Pool) == 0:
trans._func_count = cur_count + 1
# 注册 CExport 函数到全局表
if (has_export != 0 or has_state != 0) and trans.ModuleSha1 is not None:
self.Gen.CallGenBase.register_cexport_func(trans.ModuleSha1, fd.name)
# 添加参数
args_node: ast.Arguments* = fd.args
if args_node is not None:
ags: ast.Arguments* = ast.Arguments*(args_node)
if ags.args is not None:
alist: list[ast.AST*]* = ags.args
an: sizet = len(alist)
for ai in range(an):
arg: ast.Arg* = ast.Arg*(alist.get(ai))
if arg is None or arg.arg is None: continue
# CVoid 表示空参:跳过
if arg.annotation is not None:
if self.Gen.TypeGenResolve._is_t_attr(arg.annotation, "CVoid", imported_modules) != 0: continue
param_ty: llvmlite.LLVMType* = i32_ty
if arg.annotation is not None:
resolved: llvmlite.LLVMType* = self.Gen.TypeGenResolve.resolve_annotation_type(pool, arg.annotation, imported_modules, from_imports, trans, 0)
if resolved is None:
# [S4 fail-fast] 有注解但解析失败:不再静默用 i32
# (declare 与 define 签名不一致 → ABI 错位,运行期读栈垃圾)
self.Gen.TypeGenErr.fatal_error(arg, f"前向声明形参 '{arg.arg}' 类型注解解析失败", "NameError")
return 0
# 裸类形参 → Ptr(struct)(对象即指针,与方法形参一致)
# CArray 形参 → 元素指针 ty*(C 数组衰减,与 add_param 一致)
# 例外(三处必须同步:本处 / translate_function_def 的 extern
# 声明分支 / VpiReader 注入侧 _AggregateParamTy):
# C ABI 外部声明(t.CExtern/t.State,本模块无 define 侧)的
# 裸结构体形参按值 %Struct —— 真实被调方在 DLL/CRT,形参 ABI
# 由 C 头决定。TPC 定义侧同为按值(TransPyC/lib/core/Handles/
# HandlesTypeMerge.py L940-946「仅 IsStruct 吸收 1 层 CPtr」
# + LLVMCG/TypeConvert.py L137-143「CStruct → 具名结构体值」)。
# 值参数要求具名类型有**完整定义**(llvm-as 实测:opaque/未定义
# 具名类型作值参数 ⇒ "invalid type for function argument"),
# 故判据 = 该结构体在注册表可查(find_struct_by_type 命中,
# 先例 VpiReader._ensure_full_value_types L2633),命中则先
# 注册完整定义再按值(ensure_struct_def_in_module,先例
# CallGenCtor.vp L478);不命中(真 opaque)保持 Ptr(struct)。
match resolved:
case llvmlite.LLVMType.Void():
# void 不是合法形参类型(用户 2026-10-01:void 只能用于
# `void*` 与 `typedef 不透明结构体 = void`)。放任会按
# LLVM void 建形参 ⇒ 非法 IR 拖到 llc 才暴露,改编译期 fail-fast。
# 注意 `void*` 已在上游归并为 i8*,不会命中此分支。
self.Gen.TypeGenErr.fatal_error(arg, f"形参 '{arg.arg}' 不能是 void 类型(void 只能用于 void* 与 typedef 别名)", "TypeError")
return 0
case llvmlite.LLVMType.Struct(_, _, _):
if is_extern_decl != 0 and self.Gen.StructGen.find_struct_by_type(resolved) is not None:
self.Gen.StructGen.ensure_struct_def_in_module(pool, mod, resolved)
param_ty = resolved
else:
param_ty = llvmlite.Ptr(pool, resolved)
case llvmlite.LLVMType.Array(aelem_ty, _):
param_ty = llvmlite.Ptr(pool, aelem_ty)
case _:
param_ty = resolved
pname: str = pool.alloc(32)
if pname is not None:
viperlib.snprintf(pname, 32, "%%%s", arg.arg)
llvmlite.add_param(pool, func, param_ty, pname)
# *args 变长参数:设置 IsVarArg=1,生成 ... 后缀
if ags.vararg is not None:
func.IsVarArg = 1
# 参数添加完成,补全全局函数表的 Spec(供 vtable 在 func 被 reset 后派生类型文本)
self.Gen.CallGenLeafKit.update_global_func_spec(fd.name, func)
# 泛型函数上下文用完即清(防泄漏到后续函数的注解解析)
if tp_names_fd is not None:
self.Gen.TypeGenBase.clear_generic_context()
# 恢复原始声明模式
trans._declare_only = saved_declare_only
return 0
# ============================================================
# 翻译函数定义 FunctionDef(name, args, body, ...)
#
# trans 单参模式:所有共享状态从 trans 获取
# 函数局部作用域通过 enter_scope/exit_scope 管理
# ============================================================
def translate_function_def(self, trans: HT.Translator*,
node: ast.AST*) -> int:
"""翻译函数定义,返回新增的变量数(通常为 0,函数定义不增加当前作用域变量)"""
fd: ast.FunctionDef* = ast.FunctionDef*(node)
if fd is None or fd.name is None:
return 0
# async def(TPV-M1 协程):FLAG_IS_ASYNC=1(includes/ast/stmts.vp L342-345,
# 解析器把 async def 存为 FunctionDef 且 flags & 1)。
# → 走 AsyncGenMixin 状态机翻译(create_<name>/resume_<name>),
# 早返回不进普通函数路径(普通路径生成 ret 型普通函数,无法挂起/恢复)。
if fd.flags is not None and (fd.flags & 1) != 0:
return self.Gen.AsyncGen.translate_async_function(trans, node)
pool: memhub.MemBuddy* = trans.Pool
mod: llvmlite.LLVMModule* = trans.Module
imported_modules: str = trans._imported_modules
from_imports: str = trans._from_imports
funcs_ptr: GenTypes.FuncEntry* = trans._funcs
func_count: int = trans._func_count
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
# 推断返回类型:优先使用返回类型注解
ret_ty: llvmlite.LLVMType* = None
if fd.returns is not None:
ret_ty = self.Gen.TypeGenResolve.resolve_annotation_type(pool, fd.returns, imported_modules, from_imports, trans, 0)
# 单独 t.CExport 返回注解(def free(...) -> t.CExport:)= 导出
# 修饰符,无实际返回类型 → Void(根因:CExport 被 map_t_type 回退
# 为 i32 → 掉尾检查强制 return i32,mm.vp free 根因)。
# 混合实际类型(-> t.CExport | int)时保持解析结果。
if fd.returns.kind() == ast.ASTKind.Attribute:
ce_at2: ast.Attribute* = ast.Attribute*(fd.returns)
if ce_at2.attr is not None and string.strcmp(ce_at2.attr, "CExport") == 0:
if ce_at2.value is not None and ce_at2.value.kind() == ast.ASTKind.Name:
ce_nm2: ast.Name* = ast.Name*(ce_at2.value)
if ce_nm2.id is not None and string.strcmp(ce_nm2.id, "t") == 0:
ret_ty = llvmlite.Void(pool)
# 如果返回类型注解纯装饰器标记(如 t.State,无实际类型),使用 void
# 注意:必须在 infer_return_type 之前检测,因为 infer_return_type 至少返回 i32
if ret_ty is None and fd.returns is not None:
if self.Gen.TypeGenErr.has_decorator_marker(fd.returns, "State", 0) != 0:
ret_ty = llvmlite.Void(pool)
# @c.CReturn 装饰器已移除:遇到即编译期报错(多返回值改用 -> tuple[...])
if ret_ty is None:
self.Gen.FuncGenBase.RejectCReturnDecorator(fd, fd.decorator_list)
# 如果仍然为 None,扫描 return 语句推断(至少返回 i32)
if ret_ty is None:
# fail-fast:无返回类型注解(fd.returns is None)但函数体返回了
# 非 None 值 → 报错,不静默推断。返回具体值必须有显式 -> 注解,
# 编译器不替用户推断返回类型(推断位宽会掩盖返回契约,且让
# __doc__ 等依赖精确返回类型的检查静默出错)。无注解函数只允许
# 过程形态:无 return / 裸 return / return None(掉尾默认零值返回)。
if fd.returns is None:
if self.Gen.TypeGenErr.body_has_value_return(pool, fd.children) != 0:
rtn_err: str = pool.alloc(256)
if rtn_err is not None:
viperlib.snprintf(rtn_err, 256, "函数 '%s' 无返回类型注解却返回了非 None 值,请添加显式返回类型注解(如 -> int)", fd.name)
self.Gen.TypeGenErr.fatal_error(fd, rtn_err, "TypeError")
return 0
self.Gen.TypeGenErr.fatal_error(fd, "函数无返回类型注解却返回了非 None 值", "TypeError")
return 0
param_types_str: str = self.Gen.TypeGenErr.build_param_types_str(pool, fd.args)
ret_ty = self.Gen.TypeGenErr.infer_return_type(pool, fd.children, param_types_str)
# 检测是否为外部声明函数(t.CExtern 或 t.State)
# 语义:t.CExtern 忽略 body 体,仅生成 declare(由链接器解析符号)
# t.State = t.CExtern + t.CExport(既是声明又是导出)
# t.CExport 导出函数不加 SHA1 前缀
# t.CExtern/t.State/t.CExport 都不加 SHA1 前缀,直接映射到 C 标准库函数名
is_extern_decl: int = 0
has_export: int = 0
has_extern: int = 0
has_state: int = 0
if fd.returns is not None:
has_extern = self.Gen.TypeGenErr.has_decorator_marker(fd.returns, "CExtern", 0)
has_state = self.Gen.TypeGenErr.has_decorator_marker(fd.returns, "State", 0)
has_export = self.Gen.TypeGenErr.has_decorator_marker(fd.returns, "CExport", 0)
# t.CExtern/t.State 忽略 body 体,仅声明(无论 body 是否为 pass)
if has_extern != 0 or has_state != 0:
is_extern_decl = 1
# 装饰器形式存储类标记(@t.CExport/@t.CExtern/@t.State/@t.CStatic),
# 对齐 TPC HandlesFunctions._extract_decorator_storage_flags(与
# forward_declare_functions 一致,保证 declare 与 define 同名同语义)。
# 用 HandlesClassDef._has_decorator 委托(Mixin 静态绑定不能 self. 跨类调)
if fd.decorator_list is not None:
if has_extern == 0 and self.Gen.ClassGenBase._has_decorator(fd.decorator_list, "CExtern") == 1:
has_extern = 1
if has_state == 0 and self.Gen.ClassGenBase._has_decorator(fd.decorator_list, "State") == 1:
has_state = 1
if has_export == 0 and self.Gen.ClassGenBase._has_decorator(fd.decorator_list, "CExport") == 1:
has_export = 1
if (has_extern != 0 or has_state != 0) and is_extern_decl == 0:
is_extern_decl = 1
# @t.TLS 一次性初始化标记(对齐 TPC HandlesFunctions.py L1223-1231)
has_tls: int = 0
if fd.decorator_list is not None:
has_tls = self.Gen.ClassGenBase._has_decorator(fd.decorator_list, "TLS")
# 自定义行为装饰器检测(@log/@skip/@repeat(3) 等):非 t 存储标记、
# 非内置(staticmethod/property/classmethod)的 Name/Name(args) 装饰器。
# 对齐 TPC HandlesFunctions.py L1161-1189 + DecoratorPass.py。首版取
# decorator_list 中第一个自定义装饰器(Python 最外层),链式嵌套后续扩展。
has_custom_decor: int = 0
decor_handler: str = None
decor_arg0: int64 = 0
if fd.decorator_list is not None:
ddn: sizet = len(fd.decorator_list)
for ddi in range(ddn):
deco: ast.AST* = fd.decorator_list.get(ddi)
if deco is None:
continue
dk: int = deco.kind()
dname: str = None
if dk == ast.ASTKind.Name:
dnm: ast.Name* = ast.Name*(deco)
dname = dnm.id
elif dk == ast.ASTKind.Call:
dcl: ast.Call* = ast.Call*(deco)
if dcl.func is not None and dcl.func.kind() == ast.ASTKind.Name:
dnm2: ast.Name* = ast.Name*(dcl.func)
dname = dnm2.id
# @repeat(3):取首个常量 int 参数(对齐 TPC L1182-1184)
if dcl.args is not None and len(dcl.args) >= 1:
da0: ast.AST* = dcl.args.get(0)
if da0 is not None and da0.kind() == ast.ASTKind.Constant:
dc0: ast.Constant* = ast.Constant*(da0)
if dc0.const_kind == ast.CONST_INT:
decor_arg0 = dc0.int_val
if dname is None:
continue
# 跳过内置装饰器
if string.strcmp(dname, "staticmethod") == 0 \
or string.strcmp(dname, "property") == 0 \
or string.strcmp(dname, "classmethod") == 0:
continue
# 跳过 t 模块存储类标记(@t.CExport/@t.CExtern/@t.State/@t.TLS/
# @t.CStatic/@t.CInline/@t.CVTable/@t.NoVTable/@t.Object/@t.CEnum
# /@t.CUnion/@t.REnum/@t.CDefine 等裸名形式——Attribute 形式
# @t.xxx 的 kind 是 Attribute,不进入本检测)
if string.strcmp(dname, "CExport") == 0 \
or string.strcmp(dname, "CExtern") == 0 \
or string.strcmp(dname, "State") == 0 \
or string.strcmp(dname, "TLS") == 0 \
or string.strcmp(dname, "CStatic") == 0 \
or string.strcmp(dname, "CInline") == 0 \
or string.strcmp(dname, "CVTable") == 0 \
or string.strcmp(dname, "NoVTable") == 0 \
or string.strcmp(dname, "Object") == 0 \
or string.strcmp(dname, "CEnum") == 0 \
or string.strcmp(dname, "CUnion") == 0 \
or string.strcmp(dname, "REnum") == 0 \
or string.strcmp(dname, "CDefine") == 0:
continue
has_custom_decor = 1
decor_handler = dname
break
# SHA1 命名空间:t.CExtern/t.State/t.CExport 不加前缀,直接用裸名
# (裸名映射到 C 标准库符号,带 sha1 前缀会导致 undefined reference)
# main 函数也不加前缀(程序入口点)
if has_extern != 0 or has_state != 0 or has_export != 0 or string.strcmp(fd.name, "main") == 0:
mangled_name: str = fd.name
else:
mangled_name: str = self.Gen.FuncGenBase._mangle_func_name(trans, fd.name, 0)
# 注册 CExport 函数到全局表(供跨模块调用查表)
# t.CExport 函数定义用裸名(@strlen),跨模块调用需查表确认用裸名而非 @{sha1}.func
if (has_export != 0 or has_state != 0) and trans.ModuleSha1 is not None:
self.Gen.CallGenBase.register_cexport_func(trans.ModuleSha1, fd.name)
if is_extern_decl != 0:
# 外部声明函数:生成 declare(仅声明,不定义)
# 先检查是否已由 forward_declare_functions 创建,避免重复 declare
existing_extern: llvmlite.Function* = self.Gen.CallGenBase.find_func_in_module(mod, mangled_name)
if existing_extern is not None: return 0
func: llvmlite.Function* = llvmlite.create_declare(pool, mod, mangled_name, ret_ty)
if func is None: return 0
# 注册到函数表
max_funcs_extern: int = 256
if self.Gen.CallGenLeafKit.add_func_to_table(funcs_ptr, func_count, fd.name, func, max_funcs_extern, None, 0, 0, pool) == 0:
trans._func_count = func_count + 1
# 添加参数(支持类型注解)
args_node_extern: ast.Arguments* = fd.args
if args_node_extern is not None:
ags_e: ast.Arguments* = ast.Arguments*(args_node_extern)
if ags_e.args is not None:
alist_e: list[ast.AST*]* = ags_e.args
an_e: sizet = len(alist_e)
for ai_e in range(an_e):
arg_e: ast.Arg* = ast.Arg*(alist_e.get(ai_e))
if arg_e is not None and arg_e.arg is not None:
# CVoid 表示空参:跳过,不添加到函数签名
if arg_e.annotation is not None \
and self.Gen.TypeGenResolve._is_t_attr(arg_e.annotation, "CVoid", imported_modules) != 0:
continue
param_ty_e: llvmlite.LLVMType* = i32_ty
if arg_e.annotation is not None:
resolved_e: llvmlite.LLVMType* = self.Gen.TypeGenResolve.resolve_annotation_type(pool, arg_e.annotation, imported_modules, from_imports, trans, 0)
if resolved_e is None:
# fail-fast:外部声明函数参数有注解但类型解析失败,
# 不再静默保持 i32(声明签名错误会在 ABI 层暴露)
self.Gen.TypeGenErr.fatal_error(arg_e, f"参数 '{arg_e.arg}' 类型解析失败: {self.Gen.TypeGenResolve.annotation_to_str(arg_e.annotation)}", "NameError")
resolved_e = i32_ty # 不可达(fatal_error 已退出)
if resolved_e is not None:
# 裸类形参 → Ptr(struct)(对象即指针,与方法形参一致)
# CArray 形参 → 元素指针 ty*(C 数组衰减)
# 本分支恒为 C ABI 外部声明(is_extern_decl != 0,见
# 上方 if):裸结构体形参按值 %Struct(判据与降级
# 同 forward_declare_functions / VpiReader
# _AggregateParamTy,三处必须同步)。
match resolved_e:
case llvmlite.LLVMType.Void():
# void 不是合法形参类型(用户 2026-10-01,见上方同款判据)
self.Gen.TypeGenErr.fatal_error(arg_e, f"形参 '{arg_e.arg}' 不能是 void 类型(void 只能用于 void* 与 typedef 别名)", "TypeError")
case llvmlite.LLVMType.Struct(_, _, _):
if self.Gen.StructGen.find_struct_by_type(resolved_e) is not None:
self.Gen.StructGen.ensure_struct_def_in_module(pool, mod, resolved_e)
param_ty_e = resolved_e
else:
param_ty_e = llvmlite.Ptr(pool, resolved_e)
case llvmlite.LLVMType.Array(aelem_ty_e, _):
param_ty_e = llvmlite.Ptr(pool, aelem_ty_e)
case _:
param_ty_e = resolved_e
pname_e: str = pool.alloc(32)
if pname_e is not None:
viperlib.snprintf(pname_e, 32, "%%%s", arg_e.arg)
llvmlite.add_param(pool, func, param_ty_e, pname_e)
# 提取 @c.Attribute 装饰器属性并设置到函数
func_attrs_e: str = self.Gen.FuncGenBase.extract_func_attrs(pool, fd.decorator_list, imported_modules)
if func_attrs_e is not None:
llvmlite.function_set_attrs(func, func_attrs_e)
# B5:section 字符串属性走属性组 #N
func_section_e: str = self.Gen.FuncGenBase.extract_func_section(pool, fd.decorator_list, imported_modules)
if func_section_e is not None:
llvmlite.function_set_attr_group(func, func_section_e)
# 参数添加完成,补全全局函数表的 Spec
self.Gen.CallGenLeafKit.update_global_func_spec(fd.name, func)
return 0
# args_node 用于后续 alloca 创建,提前赋值
args_node: ast.Arguments* = fd.args
# 检查是否已有前向声明(由 forward_declare_functions 创建)
func: llvmlite.Function* = self.Gen.CallGenBase.find_func_in_module(mod, mangled_name)
if func is not None and llvmlite.function_is_declared(func) != 0:
# 复用前向声明:清除 IsDeclared 标记,转为 define
func.IsDeclared = 0
# 装饰器属性设置(前向声明时未设置)
func_attrs_reuse: str = self.Gen.FuncGenBase.extract_func_attrs(pool, fd.decorator_list, imported_modules)
if func_attrs_reuse is not None:
llvmlite.function_set_attrs(func, func_attrs_reuse)
# B5:section 字符串属性走属性组 #N
func_section_reuse: str = self.Gen.FuncGenBase.extract_func_section(pool, fd.decorator_list, imported_modules)
if func_section_reuse is not None:
llvmlite.function_set_attr_group(func, func_section_reuse)
else:
# 创建新的 LLVM 函数(使用 SHA1 混淆名)
func = llvmlite.create_function(pool, mod, mangled_name, ret_ty)
if func is None:
VLogger.error(f"create_function {fd.name} failed", "FUNC")
return 0
# 提取 @c.Attribute 装饰器属性并设置到函数
func_attrs: str = self.Gen.FuncGenBase.extract_func_attrs(pool, fd.decorator_list, imported_modules)
if func_attrs is not None:
llvmlite.function_set_attrs(func, func_attrs)
# B5:section 字符串属性走属性组 #N(LLVM 不接受内联 section="...")
func_section: str = self.Gen.FuncGenBase.extract_func_section(pool, fd.decorator_list, imported_modules)
if func_section is not None:
llvmlite.function_set_attr_group(func, func_section)
# 提取默认参数信息
tfd_defaults: t.CPtr = None
tfd_default_count: int = 0
tfd_param_count: int = 0
if args_node is not None:
tfd_ags: ast.Arguments* = ast.Arguments*(args_node)
if tfd_ags.args is not None:
tfd_alist: list[ast.AST*]* = tfd_ags.args
tfd_param_count = len(tfd_alist)
if tfd_ags.defaults is not None:
tfd_dlist: list[ast.AST*]* = tfd_ags.defaults
tfd_defaults = tfd_dlist
tfd_default_count = len(tfd_dlist)
# 注册到函数表
max_funcs: int = 1024
if self.Gen.CallGenLeafKit.add_func_to_table(funcs_ptr, func_count, fd.name, func, max_funcs,
tfd_defaults, tfd_default_count, tfd_param_count,
trans.Pool) == 0:
trans._func_count = func_count + 1
# 添加参数(支持类型注解)
if args_node is not None:
ags: ast.Arguments* = ast.Arguments*(args_node)
if ags.args is not None:
alist: list[ast.AST*]* = ags.args
an: sizet = len(alist)
for ai in range(an):
arg: ast.Arg* = ast.Arg*(alist.get(ai))
if arg is not None and arg.arg is not None:
# CVoid 表示空参:跳过,不添加到函数签名
if arg.annotation is not None \
and self.Gen.TypeGenResolve._is_t_attr(arg.annotation, "CVoid", imported_modules) != 0:
continue
param_ty: llvmlite.LLVMType* = i32_ty
if arg.annotation is not None:
resolved: llvmlite.LLVMType* = self.Gen.TypeGenResolve.resolve_annotation_type(pool, arg.annotation, imported_modules, from_imports, trans, 0)
if resolved is None:
# [S4 fail-fast] 有注解但解析失败:不再静默用 i32
# (形参类型错 → ABI 错位/字段访问错)
self.Gen.TypeGenErr.fatal_error(arg, f"形参 '{arg.arg}' 类型注解解析失败", "NameError")
return 0
# 裸类形参 → Ptr(struct)(对象即指针,与方法形参一致)
# CArray 形参 → 元素指针 ty*(C 数组衰减:final(out: t.CArray[..., N])
# 的 out 指向调用方数组首元素;传 Ptr(数组) 会使 out[i] 的
# GEP 以整个数组为步长错位,摘要垃圾根因)
match resolved:
case llvmlite.LLVMType.Void():
# void 不是合法形参类型(用户 2026-10-01,见上方同款判据)
self.Gen.TypeGenErr.fatal_error(arg, f"形参 '{arg.arg}' 不能是 void 类型(void 只能用于 void* 与 typedef 别名)", "TypeError")
return 0
case llvmlite.LLVMType.Struct(_, _, _):
param_ty = llvmlite.Ptr(pool, resolved)
case llvmlite.LLVMType.Array(aelem_ty, _):
param_ty = llvmlite.Ptr(pool, aelem_ty)
case _:
param_ty = resolved
pname: str = pool.alloc(32)
if pname is not None:
viperlib.snprintf(pname, 32, "%%%s", arg.arg)
llvmlite.add_param(pool, func, param_ty, pname)
# *args 变长参数:设置 IsVarArg=1,生成 ... 后缀
if ags.vararg is not None:
func.IsVarArg = 1
# try-except:函数体含 raise → 追加 __eh_msg_out__(i8**)/
# __eh_code_out__(i32*)输出参数(对齐 TPC HandlesFunctions.py
# L706-711;main 除外)。被调函数把异常编码/消息写入调用方传入
# 的指针,调用方 _check_eh_return 检测。
# 注意:必须在参数添加块(if args_node is not None:)外——无参函数
# (def f())的 args_node 为 None,若放在其内会被跳过,导致函数体
# store %__eh_code_out__ 但签名无此参数(llc: use of undefined value)。
if string.strcmp(fd.name, "main") != 0:
if self.Gen.FuncGenBase._body_has_raise(fd) != 0:
i8_ty_eh: llvmlite.LLVMType* = llvmlite.Int8(pool)
i8_ptr_ty_eh: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty_eh)
i8_ptr_ptr_ty_eh: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ptr_ty_eh)
i32_ty_eh: llvmlite.LLVMType* = llvmlite.Int32(pool)
i32_ptr_ty_eh: llvmlite.LLVMType* = llvmlite.Ptr(pool, i32_ty_eh)
if i8_ptr_ptr_ty_eh is not None and i32_ptr_ty_eh is not None:
llvmlite.add_param(pool, func, i8_ptr_ptr_ty_eh, "%__eh_msg_out__")
llvmlite.add_param(pool, func, i32_ptr_ty_eh, "%__eh_code_out__")
# 参数添加完成,补全全局函数表的 Spec
self.Gen.CallGenLeafKit.update_global_func_spec(fd.name, func)
# 创建 entry 块
entry_blk: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, "entry")
if entry_blk is None:
return 0
# 创建函数专属 builder
func_builder: llvmlite.IRBuilder* = llvmlite.new_builder(pool, func)
if func_builder is None:
return 0
llvmlite.position_at_end(func_builder, entry_blk)
# --traceback: attach a DISubprogram to this define and set every
# instruction in the body to the entry DILocation (the statement hook
# refines it per statement). No-op when DI is disabled.
dbg_pushed: int = DebugInfoGen.PushFunction(pool, func_builder, func,
fd.lineno, fd.col_offset + 1)
# @t.TLS 一次性初始化守卫(对齐 TPC HandlesFunctions.py):首次调用执行函数体并置
# 全局标志 __tls_init_done_{name}=1,后续调用直接返回默认值。不实现则每次调用都
# TlsAlloc,provider 栈跨调用丢失。
if has_tls != 0:
tls_flag_name: str = pool.alloc(128)
if tls_flag_name is not None:
viperlib.snprintf(tls_flag_name, 128, "__tls_init_done_%s", fd.name)
tls_flag_gv: llvmlite.GlobalVariable* = llvmlite.create_global_int(pool, mod, tls_flag_name, 1, 0)
if tls_flag_gv is not None:
i1_ty_t: llvmlite.LLVMType* = llvmlite.Int1(pool)
if i1_ty_t is not None:
# GlobalVariable 不是 Value 子类(字段布局不同),build_load/store
# 按 Value 读 ptr.Ty/ptr.Name 会错位(Ty 读到 Name → void,Name 为空)。
# 与 create_global_string 一致:构造 Value 视图(Ty=Ptr(i1), Name="@name")。
tls_gv_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i1_ty_t)
tls_ref_name: str = pool.alloc(64)
if tls_ref_name is not None:
viperlib.snprintf(tls_ref_name, 64, "@%s", tls_flag_name)
tls_flag_ref: llvmlite.Value* = llvmlite.SSAValue(pool, tls_gv_ptr_ty, tls_ref_name)
if tls_flag_ref is not None:
tls_flag_ld: llvmlite.Value* = llvmlite.build_load(func_builder, i1_ty_t, tls_flag_ref)
# 块名唯一化(create_block 不自动编号,同函数同名 label 冲突)
lc_t: int = trans._label_counter
trans._label_counter = lc_t + 1
tls_bb_buf: str = pool.alloc(64)
if tls_bb_buf is not None:
viperlib.snprintf(tls_bb_buf, 64, "tls.skip.%d", lc_t)
tls_skip_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, tls_bb_buf)
viperlib.snprintf(tls_bb_buf, 64, "tls.cont.%d", lc_t)
tls_cont_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, tls_bb_buf)
if tls_skip_bb is not None and tls_cont_bb is not None:
llvmlite.build_cond_br(func_builder, tls_flag_ld, tls_skip_bb, tls_cont_bb)
# skip 块:按返回类型生成默认值直接返回
llvmlite.position_at_end(func_builder, tls_skip_bb)
match ret_ty:
case llvmlite.LLVMType.Void():
llvmlite.build_ret_void(func_builder)
case llvmlite.LLVMType.Int(_):
tlz0: llvmlite.Value* = llvmlite.ConstInt(pool, ret_ty, 0, "0")
if tlz0 is not None:
llvmlite.build_ret(func_builder, tlz0)
case llvmlite.LLVMType.Float(_):
tlf0: llvmlite.Value* = llvmlite.ConstFloat(pool, ret_ty, 0.0)
if tlf0 is not None:
llvmlite.build_ret(func_builder, tlf0)
case _:
tln0: llvmlite.Value* = llvmlite.ConstNull(pool, ret_ty, "null")
if tln0 is not None:
llvmlite.build_ret(func_builder, tln0)
# cont 块:置标志=1,继续函数体
llvmlite.position_at_end(func_builder, tls_cont_bb)
tlone: llvmlite.Value* = llvmlite.ConstInt(pool, i1_ty_t, 1, "1")
if tlone is not None:
llvmlite.build_store(func_builder, tlone, tls_flag_ref)
# 进入函数作用域(嵌套符号表)
self.Gen.VarGen.enter_scope(trans.SymTab, FuncGenMixin.SCOPE_FUNCTION)
# PEP 695 泛型函数: def f[T](...) — 设置泛型上下文,类型参数映射到 "int" 兜底。
# TPV 无泛型函数特化机制(类泛型走 _specialize_generic_class),泛型函数按普通
# 函数编译;设置上下文使参数注解 T / 方法体中的 T(x) 转换可解析为 int。
# (注意与类特化的 set_generic_context 一样是全局状态,需在退出作用域前清除。)
tp_names_fn: list[str]* = None
if fd.type_params is not None:
tp_names_fn = fd.type_params
tp_args_fn: list[str]* = list[str](pool, 8)
if tp_args_fn is not None:
tpn_fn: sizet = len(fd.type_params)
tpi_fn: sizet = 0
for tpi_fn in range(tpn_fn):
tp_args_fn.append("int")
self.Gen.TypeGenBase.set_generic_context(tp_names_fn, tp_args_fn)
# 为参数创建 alloca
if args_node is not None:
ags2: ast.Arguments* = ast.Arguments*(args_node)
if ags2.args is not None:
alist2: list[ast.AST*]* = ags2.args
an2: sizet = len(alist2)
for ai2 in range(an2):
arg2: ast.Arg* = ast.Arg*(alist2.get(ai2))
if arg2 is not None and arg2.arg is not None:
# CVoid 表示空参:跳过,不创建 alloca
if arg2.annotation is not None:
if self.Gen.TypeGenResolve._is_t_attr(arg2.annotation, "CVoid", imported_modules) != 0:
continue
param_ty2: llvmlite.LLVMType* = i32_ty
if arg2.annotation is not None:
resolved2: llvmlite.LLVMType* = self.Gen.TypeGenResolve.resolve_annotation_type(pool, arg2.annotation, imported_modules, from_imports, trans, 0)
if resolved2 is None:
# fail-fast:参数有注解但类型解析失败,不再静默保持 i32
self.Gen.TypeGenErr.fatal_error(arg2, f"参数 '{arg2.arg}' 类型解析失败: {self.Gen.TypeGenResolve.annotation_to_str(arg2.annotation)}", "NameError")
resolved2 = i32_ty # 不可达(fatal_error 已退出)
if resolved2 is not None:
# 与 add_param 保持一致:裸类形参 → Ptr(struct)(对象即指针);
# CArray 形参 → 元素指针 ty*(数组衰减,alloca 类型须与形参一致,
# 否则 store ty* 到 [N x ty]* 容器类型不匹配)
match resolved2:
case llvmlite.LLVMType.Void():
# void 不是合法形参类型(用户 2026-10-01,见上方同款判据)
self.Gen.TypeGenErr.fatal_error(arg2, f"形参 '{arg2.arg}' 不能是 void 类型(void 只能用于 void* 与 typedef 别名)", "TypeError")
return 0
case llvmlite.LLVMType.Struct(_, _, _):
param_ty2 = llvmlite.Ptr(pool, resolved2)
case llvmlite.LLVMType.Array(aelem_ty2, _):
param_ty2 = llvmlite.Ptr(pool, aelem_ty2)
case _:
param_ty2 = resolved2
alloca: llvmlite.Value* = llvmlite.build_alloca(func_builder, param_ty2)
if alloca is not None:
self.Gen.VarGen.define_var(trans.SymTab, arg2.arg, alloca)
# 存储原始类型注解的类名(方法调用检测时,Ptr(i8) 回退到类名查找结构体)
# 传 pool:泛型 Subscript 返回 mangled name(对齐 HandlesAnnAssign 修复)
cls_nm: str = None
if arg2.annotation is not None:
cls_nm = self.Gen.TypeGenResolve.extract_class_name_from_annotation(arg2.annotation, imported_modules, pool, trans._from_imports)
if cls_nm is not None:
self.Gen.VarGen.set_var_annot_class_name(trans.SymTab, arg2.arg, cls_nm)
# t.CVolatile 形参:声明期标记,函数体内该参数名的
# load/store 带 volatile(volatile 参数对象的读改写不得
# 被优化器提升/合并,如自旋等待入参)。
if arg2.annotation is not None:
# const 形参:**沿用 TPC 形参的历史判据**(只看注解
# 是否含 t.CConst,不看指针层数)——TPC 形参登记点
# HandlesFunctions 的 IsParam=True 用同一条件,两侧逐条
# 对齐(见 Debugger/type-descriptors.md 已知差异)。
if self.Gen.TypeGenErr.has_decorator_marker(arg2.annotation, "CConst", 0) != 0:
self.Gen.VarGen.set_var_const(trans.SymTab, arg2.arg)
if self.Gen.TypeGenErr.has_decorator_marker(arg2.annotation, "CVolatile", 0) != 0:
self.Gen.VarGen.set_var_volatile(trans.SymTab, arg2.arg)
# rawptr[t.CVolatile | T] 形参(volatile 指针指向物):
# 函数体内该参数解引用(p[i]/p.field/c.Deref(p))带 volatile。
if self.Gen.TypeGenErr.has_pointee_volatile_marker(arg2.annotation) != 0:
self.Gen.VarGen.set_var_pointee_volatile(trans.SymTab, arg2.arg)
pname2: str = pool.alloc(32)
if pname2 is not None:
viperlib.snprintf(pname2, 32, "%%%s", arg2.arg)
param_val: llvmlite.Value* = llvmlite.SSAValue(pool, param_ty2, pname2)
vol_p2: int = self.Gen.VarGen.var_is_volatile(self.Gen.VarGen.lookup_var_entry(trans.SymTab, arg2.arg))
llvmlite.build_store(func_builder, param_val, alloca, vol_p2)
# *args 变长参数:创建 va_list 缓冲区 + 调用 va_start + 注册到符号表
# 生成 IR:
# %args_va = alloca [24 x i8], align 16 ; va_list 缓冲区(Win64 __va_list_tag)
# %args = bitcast [24 x i8]* %args_va to i8*
# call void @llvm.va_start(i8* %args) ; 初始化 va_list
# 用户函数体内可通过 args 名字读取 va_list 地址(i8*),或用 arg(type) 糖函数
# 注意:必须在参数 alloca 段(if args_node is not None:)内但 EH 块外——
# 无 raise 的函数(viperlib.sprintf 等)同样有 *args,若放在 EH 块内
# 会被跳过,args 未注册到符号表 → NameError: 未定义名称 'args'。
if ags2.vararg is not None:
vararg_node: ast.Arg* = ast.Arg*(ags2.vararg)
if vararg_node is not None and vararg_node.arg is not None:
vararg_name_str: str = vararg_node.arg
# va_list 缓冲区 24 字节(Win64 的 __va_list_tag = {i32,i32,i8*,i8*})+ 16 对齐
# (对齐 TPC HandlesFunctions.py:1739-1741)
i8_ty_va: llvmlite.LLVMType* = llvmlite.Int8(pool)
i8_ptr_ty_va: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty_va)
va_buf_ty: llvmlite.LLVMType* = llvmlite.Array(pool, i8_ty_va, 24)
va_list_alloca: llvmlite.Value* = llvmlite.build_alloca_aligned(func_builder, va_buf_ty, 16)
if va_list_alloca is not None:
# i8* 地址(指向 24 字节 va_list 缓冲区)——vararg 名的值语义
va_list_addr: llvmlite.Value* = llvmlite.build_bitcast(func_builder, va_list_alloca, i8_ptr_ty_va)
if va_list_addr is not None:
# 注册到符号表(translate_name_value 对 vararg 名特殊处理返回地址)
self.Gen.VarGen.define_var(trans.SymTab, vararg_name_str, va_list_alloca)
# 调用 @llvm.va_start(i8* %va_list_addr)
void_ty_va: llvmlite.LLVMType* = llvmlite.Void(pool)
llvmlite.build_call(func_builder, "llvm.va_start",
va_list_addr, 1, void_ty_va, 0)
# 保存到 trans 供 arg(type) 糖函数与 vararg 名翻译使用
trans._va_list_ptr = va_list_addr
trans._vararg_name = vararg_name_str
# try-except:新函数作用域 EH 状态从零开始。必须先保存外层函数
# (调用方/包围函数)的 EH 输出参数,翻译完本函数后再恢复——否则
# 下方设置本函数 EH 参数会覆盖外层值,恢复时 old_eh_* 拿到的是
# 本函数自身参数(嵌套函数/多函数链 EH 状态错乱)。
old_eh_msg_out: llvmlite.Value* = trans._eh_msg_out_param
old_eh_code_out: llvmlite.Value* = trans._eh_code_out_param
old_cur_func_has_eh: int = trans._cur_func_has_eh
trans._eh_msg_out_param = None
trans._eh_code_out_param = None
trans._cur_func_has_eh = 0
# try-except:保存当前函数的 EH 输出参数(__eh_msg_out__/__eh_code_out__)
# 供 translate_raise / UnhandledBB 写入并向上传播。无 EH 参数的函数置空。
if string.strcmp(fd.name, "main") != 0 and self.Gen.FuncGenBase._body_has_raise(fd) != 0:
i8_ty_eh2: llvmlite.LLVMType* = llvmlite.Int8(pool)
i8_ptr_ty_eh2: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty_eh2)
i8_ptr_ptr_ty_eh2: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ptr_ty_eh2)
i32_ty_eh2: llvmlite.LLVMType* = llvmlite.Int32(pool)
i32_ptr_ty_eh2: llvmlite.LLVMType* = llvmlite.Ptr(pool, i32_ty_eh2)
if i8_ptr_ptr_ty_eh2 is not None and i32_ptr_ty_eh2 is not None:
msg_out_ref: llvmlite.Value* = llvmlite.SSAValue(pool, i8_ptr_ptr_ty_eh2, "%__eh_msg_out__")
code_out_ref: llvmlite.Value* = llvmlite.SSAValue(pool, i32_ptr_ty_eh2, "%__eh_code_out__")
trans._eh_msg_out_param = msg_out_ref
trans._eh_code_out_param = code_out_ref
trans._cur_func_has_eh = 1
# 保存模块级作用域状态(仅非变量表相关)
old_func: llvmlite.Function* = trans._cur_func
old_builder: llvmlite.IRBuilder* = trans._cur_builder
old_global_count: int = trans._global_name_count
old_nonlocal_count: int = trans._nonlocal_name_count
old_env_count: int = trans._closure_env_count
old_va_list_ptr: llvmlite.Value* = trans._va_list_ptr
old_vararg_name: str = trans._vararg_name
# 返回注解上下文([C①] 裸名泛型构造的类型实参回退来源之一):
# 进入函数体前记录本函数返回注解,退出时恢复外层函数的值
old_ret_annot: ast.AST* = trans.CurFuncRetAnnot
trans._cur_func = func
trans._cur_builder = func_builder
trans.CurFuncRetAnnot = fd.returns
# 清空 global/nonlocal 名称集合(新函数作用域)
GenApi.clear_scope_names(trans)
# 重置链内 nonlocal 堆预建标志(每函数只建一次;多嵌套函数定义
# 共享同一堆,防重复 malloc + 二次重定向 VarEntry)
trans._nl_chain_done = 0
# 预扫描函数体:
# 1. 先预扫描 Global/Nonlocal 声明(Python 语义:global/nonlocal
# 对整个函数作用域生效,与声明位置无关,故须在任何赋值前注册)
# 2. 再预扫描 AnnAssign 为局部变量提前创建 alloca
body: list[ast.AST*]* = fd.children
if body is not None:
bn: sizet = len(body)
for bi in range(bn):
stmt: ast.AST* = body.get(bi)
if stmt is not None:
self.Gen.StmtGenDecl.pre_scan_scope_decls(trans, stmt)
for bi in range(bn):
stmt: ast.AST* = body.get(bi)
if stmt is not None:
self.Gen.StmtGenDecl.pre_scan_allocas(trans, stmt)
# 翻译函数体
if body is not None:
bn2: sizet = len(body)
for bi2 in range(bn2):
stmt2: ast.AST* = body.get(bi2)
if stmt2 is not None:
# 嵌套函数定义前:预扫描其链内 nonlocal 并建堆
# (不同层捕获不同变量的场景,见 _prepare_chain_nonlocals)
if stmt2.kind() == ast.ASTKind.FunctionDef:
self.Gen.FuncGen._prepare_chain_nonlocals(trans, stmt2, pool, func_builder, mod, llvmlite.Int8(pool), llvmlite.Ptr(pool, llvmlite.Int8(pool)))
self.Gen.StmtGen.translate_stmt(trans, stmt2)
# 如果函数体最后一条语句不是 Return,添加隐式 ret
last_is_return: int = 0
# 追加89:bn3 提前初始化,避免 body is None 时下方 fail-fast 分支
# 引用未定义的 bn3(追加81 同款 NameError 风险)
bn3: sizet = 0
if body is not None:
bn3 = len(body)
if bn3 > 0:
last_stmt: ast.AST* = body.get(bn3 - 1)
if last_stmt is not None and last_stmt.kind() == ast.ASTKind.Return:
last_is_return = 1
if last_is_return == 0:
if llvmlite.builder_cur_block_is_terminated(func_builder) == 0:
# 编译器不替代码发明返回值——函数流程真实掉出末尾而未显式 return 时 fail-fast
# (要求补 return,定位到函数)。三种合法收尾:
# ① void 函数掉出末尾 → ret void(无值可发明,Python 语义)
# ② 末句是控制流语句(match/if 全分支 return)且当前块未 terminated →
# merge 块结构性不可达 → unreachable
# ③ 无返回类型注解的函数(fd.returns is None,过程风格函数)→ 视为无返回值
# 函数,默认生成零值返回(ConstZero 按推断出的 ret_ty 构造,类型匹配)
# 有 -> 注解且末句是普通语句掉出末尾 → fail-fast(不得替代码发明返回值,也不做
# noreturn 函数名白名单——错误终止路径也必须在源码层面保证块收尾)。
# 末句是否为控制流语句(If/Match/While/For/Try/With):翻译后当前块未 terminated
# 表示 merge 块结构性不可达(所有分支均已 return/terminated)——对非 void 函数
# 生成 unreachable 而非 fail-fast(GCC/Clang 对 fall-through 视为 UB 同语义)。
last_is_ctrl: int = 0
if bn3 > 0:
last_stmt3: ast.AST* = body.get(bn3 - 1)
if last_stmt3 is not None:
k3: int = last_stmt3.kind()
if k3 == ast.ASTKind.If or k3 == ast.ASTKind.While or \
k3 == ast.ASTKind.For or k3 == ast.ASTKind.Try or \
k3 == ast.ASTKind.With or k3 == ast.ASTKind.Match:
last_is_ctrl = 1
_is_void: int = 0
if ret_ty is not None:
match ret_ty:
case llvmlite.LLVMType.Void():
_is_void = 1
case _:
pass
# 返回注解层面的"无返回值"判据(与上面的 ret_ty 类型判定互为双保险,
# 不改变任何非 void 分支):LLVMType 的 REnum class-pattern match 一旦退化
# (变体表/类名失配 → _handle_simple_match 不产出 case 值),_is_void 恒 0,
# 会把 c.Asm 收尾的 void 函数(流程真实掉出末尾)误报成"缺显式 return";
# 报文的"(返回类型 void)"不能作为判据(TypePrint 的 `case _` 兜底同样打印
# void,任何未命中类型都显示 void)。故按注解判据补足,与注解→类型解析同口径
# (注解声明无返回值 ⇔ 解析为 LLVMType.Void):① t\.CVoid(Attribute 形式)
# ② 裸名 CVoid(from t import CVoid)③ -> None(CONST_NONE);
# ①②统一经既有判据 TypeGenResolve._is_cvoid_marker 判定(不新增名字白名单)。
if _is_void == 0 and fd.returns is not None:
if self.Gen.TypeGenResolve._is_cvoid_marker(fd.returns, imported_modules) != 0:
_is_void = 1
elif fd.returns.kind() == ast.ASTKind.Constant:
ret_none_cn: ast.Constant* = (ast.Constant*)(fd.returns)
if ret_none_cn.const_kind == ast.CONST_NONE:
_is_void = 1
if _is_void != 0:
llvmlite.build_ret_void(func_builder)
elif last_is_ctrl != 0 and trans._ctrl_merge_reachable == 0:
# 追加90:非 void 函数末句是控制流且 merge 块**结构性**不可达
# (全分支 return,无 br 到 merge)→ LLVM 语义 unreachable。
# merge 可达(分支 br 到 merge,如 testcheck.check 的 if/else 无 return)
# 时不是结构性不可达,需正常收尾(下方 ConstZero / fail-fast):可达块的
# unreachable 是 UB,llc 不生成任何指令 ⇒ 执行掉进布局紧随其后的块。
# ★ 可达性判据**只用 `_ctrl_merge_reachable`**(MatchGenMixin 逐臂真正
# `br end_bb` 时才置 1,并由"用本 match 自身的 br 记录覆盖"写回):
# 实测反面教材 —— includes/llvmlite/__types.vp::_TypePrintDepth 末句
# `match ty:` 带 `case _:`,各臂只 snprintf 后 br 到 merge;旧判据(追加92
# 的 MatchHasWildcardArm 子句)按"穷尽 ⇒ 流程不可能掉出末尾"推断,给这个
# 可达 merge 生成了 unreachable ⇒ 打印完 "i32" 后掉进同一 switch 的跳转表,
# 用上一条 snprintf 的返回值("i%d" → 3)当 tag 取 table[3] = Array 臂,
# 把 Int 的 Bits(32) 当指针递归解引用 ⇒ AV at 0x20。
# 穷尽性 ≠ 各臂都终止:只有"有没有 br 到 merge"才是可达性。
llvmlite.build_unreachable(func_builder)
elif fd.returns is None:
# 无返回类型注解 → 无返回值过程函数,默认零值返回
if ret_ty is not None:
zero_val: llvmlite.Value* = llvmlite.ConstZero(pool, ret_ty)
if zero_val is not None:
llvmlite.build_ret(func_builder, zero_val)
else:
self.Gen.TypeGenErr.fatal_error(node, "函数流程掉出末尾但未显式 return", "TypeError")
else:
self.Gen.TypeGenErr.fatal_error(node, "函数流程掉出末尾但未显式 return", "TypeError")
else:
# fail-fast:有 -> 注解但流程真实掉出末尾(定位到函数定义
# 节点,fatal_error 输出 traceback 风格错误)
if ret_ty is not None:
# llvmlite 无 type_get_name API,类型序列化用真实接口
# TypePrint(buf, size, ty, pool)(追加89 修正)
rt_name: str = pool.alloc(64)
if rt_name is not None:
llvmlite.TypePrint(rt_name, 64, ret_ty, pool)
if rt_name[0] == '\0':
rt_name = "?"
err_fn: str = pool.alloc(256)
if err_fn is not None:
viperlib.snprintf(err_fn, 256, "函数 '%s' 流程掉出函数末尾但未显式 return(返回类型 %s),请补显式 return(如 return 0 / return null)", fd.name, rt_name)
self.Gen.TypeGenErr.fatal_error(node, err_fn, "TypeError")
self.Gen.TypeGenErr.fatal_error(node, "函数流程掉出末尾但未显式 return", "TypeError")
else:
self.Gen.TypeGenErr.fatal_error(node, "函数流程掉出末尾但未显式 return", "TypeError")
# 恢复模块级作用域(退出函数作用域)
if tp_names_fn is not None:
self.Gen.TypeGenBase.clear_generic_context()
self.Gen.VarGen.exit_scope(trans.SymTab)
trans._cur_func = old_func
trans._cur_builder = old_builder
trans._global_name_count = old_global_count
trans._nonlocal_name_count = old_nonlocal_count
trans._closure_env_count = old_env_count
trans._va_list_ptr = old_va_list_ptr
trans._vararg_name = old_vararg_name
# 交还外层函数的返回注解([C①] 见上方 old_ret_annot)
trans.CurFuncRetAnnot = old_ret_annot
# 恢复外层函数(调用方)的 EH 输出参数——本函数体内的 raise 传播
# 使用本函数参数,翻译结束必须交还外层作用域,否则嵌套函数/链式
# 调用后 EH 状态残留导致 raise 写入错误的 out 指针。
trans._eh_msg_out_param = old_eh_msg_out
trans._eh_code_out_param = old_eh_code_out
trans._cur_func_has_eh = old_cur_func_has_eh
# 自定义装饰器:注册 + 生成 wrapper(对齐 TPC DecoratorPass.run)。
# 仅模块级函数(fd 是顶层定义);wrapper 名 __decor_wrap_{裸函数名}。
# 调用点重写经 lookup_decor_wrapper(translate_call 拦截原函数名)。
if has_custom_decor != 0:
wb_name: str = pool.alloc(128)
if wb_name is not None:
viperlib.snprintf(wb_name, 128, "__decor_wrap_%s", fd.name)
self.Gen.ClassGenBase.register_decorator(pool, fd.name, wb_name, decor_arg0)
self._gen_decor_wrapper(trans, pool, mod, func, fd.name, wb_name, decor_handler, decor_arg0)
if dbg_pushed != 0:
DebugInfoGen.PopFunction(func_builder)
return 0
# ============================================================
# _RegisterStaticFunc - static 函数登记(禁止跨模块使用)
#
# 两种书写形态同源识别(解析层已归一):
# 1) 注解形态:`def f() -> t.CVoid | t.CStatic:`(CStatic 标记在 returns 里)
# 2) 装饰器形态:`@t.CStatic` / 裸 `static def f(...)`(解析层合成装饰器)
# 命中即登记 (函数名, 定义模块 SHA1) 到 static 符号表;跨模块引用侧
# (_CheckStaticCallCrossModule / _CheckStaticFromImport / _CheckStaticCrossModule)
# 据此 fail-fast。独立成方法:translate_function_def 含多分支,内联新增分支
# 会干扰其类型推断(同 ExprGenAttr / CallGenMixin / TranslatorGenMixin 处理)。
# ============================================================
def _RegisterStaticFunc(self, trans: HT.Translator*,
fd: ast.FunctionDef*) -> int:
"""static 函数登记:returns 注解或 @t.CStatic 装饰器命中即登记;1=已登记 / 0=未命中"""
if trans is None or fd is None or fd.name is None:
return 0
if trans.ModuleSha1 is None:
return 0
has: int = 0
if fd.returns is not None:
has = self.Gen.TypeGenErr.has_decorator_marker(fd.returns, "CStatic", 0)
if has == 0 and fd.decorator_list is not None:
if self.Gen.ClassGenBase._has_decorator(fd.decorator_list, "CStatic") == 1:
has = 1
if has == 0:
return 0
return self.Gen.CallGenBase.RegisterStaticSymbol(trans.ModuleSha1, fd.name)
# ============================================================
# _gen_decor_wrapper - 生成装饰器 wrapper 函数(对齐 TPC DecoratorPass.py
# _generate_single_wrapper v4)
#
# v4 Wrapper 结构(最外层含递归保护):
# entry → 递归保护检查(最外层)
# recursive_call → 递归时直接调用原函数,跳过所有装饰
# decorated_entry → 置递归标志,分配 ctx/args/ret,调用 handler 前置
# loop_header → 计数器 i < n_calls(TPV 用 alloca 计数器替代 phi)
# loop.body → 从 args_struct 读回参数,调用原函数
# post → 调用 handler 后置,清递归标志,返回结果
#
# handler 调用约定:i32 decor(i8* ctx, i8* func_name, i32 phase,
# i8* args_ptr, i8* ret_ptr, i8* decor_args_ptr)
# 前置返回:0=跳过原函数,1=调用一次,N=循环 N 次
# ============================================================
def _gen_decor_wrapper(self, trans: HT.Translator*,
pool: memhub.MemBuddy*,
mod: llvmlite.LLVMModule*,
func: llvmlite.Function*,
func_name: str,
wrapper_name: str,
handler_name: str,
decor_arg0: int64) -> llvmlite.Function*:
"""生成装饰器 wrapper 函数,返回 wrapper 或 None"""
if trans is None or pool is None or mod is None or func is None:
return None
if func_name is None or wrapper_name is None or handler_name is None:
return None
ret_ty: llvmlite.LLVMType* = llvmlite.function_get_ret_ty(func)
if ret_ty is None:
return None
orig_call_name: str = llvmlite.function_get_name(func)
if orig_call_name is None:
return None
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty)
# ---- 收集原函数参数类型(按位置,最多 16 个)----
n_params: int = 0
param_tys: sizet* = pool.alloc(16 * 8)
if param_tys is None:
return None
string.memset(param_tys, 0, 16 * 8)
pp: llvmlite.Param* = llvmlite.function_get_param_head(func)
while pp is not None:
pty: llvmlite.LLVMType* = llvmlite.param_get_ty(pp)
if pty is not None and n_params < 16:
param_tys[n_params] = sizet(pty)
n_params += 1
pp = llvmlite.param_get_next(pp)
# ---- 创建 wrapper 函数并添加参数(名字 %a0..%aN)----
wrapper: llvmlite.Function* = llvmlite.create_function(pool, mod, wrapper_name, ret_ty)
if wrapper is None: return None
pi: int = 0
for pi in range(n_params):
pname_w: str = pool.alloc(16)
if pname_w is not None:
viperlib.snprintf(pname_w, 16, "%%a%d", pi)
llvmlite.add_param(pool, wrapper, (llvmlite.LLVMType*)(param_tys[pi]), pname_w)
# ---- 创建块 ----
entry_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, wrapper, "entry")
loop_h_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, wrapper, "loop.header")
loop_b_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, wrapper, "loop.body")
post_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, wrapper, "post")
if entry_bb is None or loop_h_bb is None or loop_b_bb is None or post_bb is None:
return None
# 递归保护标志(最外层):@__decor_rec_{wrapper} = global i8 0
rec_flag_ref: llvmlite.Value* = None
rec_flag_name: str = pool.alloc(128)
if rec_flag_name is not None:
viperlib.snprintf(rec_flag_name, 128, "__decor_rec_%s", wrapper_name)
llvmlite.create_global_int(pool, mod, rec_flag_name, 8, 0)
rec_ref_nm: str = pool.alloc(96)
if rec_ref_nm is not None:
viperlib.snprintf(rec_ref_nm, 96, "@%s", rec_flag_name)
rec_flag_ref = llvmlite.SSAValue(pool, llvmlite.Ptr(pool, i8_ty), rec_ref_nm)
wb: llvmlite.IRBuilder* = llvmlite.new_builder(pool, wrapper)
if wb is None:
return None
# 返回类型分类
ret_is_void: int = 0
match ret_ty:
case llvmlite.LLVMType.Void():
ret_is_void = 1
case _:
pass
# ---- entry:递归保护检查(最外层)----
llvmlite.position_at_end(wb, entry_bb)
loop_pred_bb: rawptr[llvmlite.BasicBlock] = entry_bb
if rec_flag_ref is not None:
rec_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, wrapper, "recursive_call")
dec_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, wrapper, "decorated_entry")
if rec_bb is None or dec_bb is None:
return None
rec_val: llvmlite.Value* = llvmlite.build_load(wb, i8_ty, rec_flag_ref)
rec_zero: llvmlite.Value* = llvmlite.ConstInt(pool, i8_ty, 0, "0")
rec_is: llvmlite.Value* = llvmlite.build_icmp(wb, llvmlite.ICMP_NE, rec_val, rec_zero)
llvmlite.build_cond_br(wb, rec_is, rec_bb, dec_bb)
# recursive_call:直接调用原函数返回(跳过所有装饰逻辑)
llvmlite.position_at_end(wb, rec_bb)
rec_args: llvmlite.Value* = None
ri: int = 0
for ri in range(n_params):
an_r: str = pool.alloc(16)
if an_r is None:
continue
viperlib.snprintf(an_r, 16, "%%a%d", ri)
av_r: llvmlite.Value* = llvmlite.SSAValue(pool, (llvmlite.LLVMType*)(param_tys[ri]), an_r)
if av_r is not None:
llvmlite.value_set_next(av_r, None)
if rec_args is None:
rec_args = av_r
else:
# 链尾追加
rt: llvmlite.Value* = rec_args
while rt.Next is not None:
rt = rt.Next
llvmlite.value_set_next(rt, av_r)
if ret_is_void != 0:
llvmlite.build_call(wb, orig_call_name, rec_args, n_params, ret_ty, 0)
llvmlite.build_ret_void(wb)
else:
rc_res: llvmlite.Value* = llvmlite.build_call(wb, orig_call_name, rec_args, n_params, ret_ty, 0)
if rc_res is not None:
llvmlite.build_ret(wb, rc_res)
else:
llvmlite.build_ret_void(wb)
# decorated_entry:置递归标志,继续装饰路径
llvmlite.position_at_end(wb, dec_bb)
rec_one: llvmlite.Value* = llvmlite.ConstInt(pool, i8_ty, 1, "1")
if rec_one is not None:
llvmlite.build_store(wb, rec_one, rec_flag_ref)
loop_pred_bb = dec_bb
# ---- 公共装饰路径(entry 或 decorated_entry)----
# 1. ctx = alloca [32 x i8]; ctx_ptr = bitcast i8*
ctx_ty: llvmlite.LLVMType* = llvmlite.Array(pool, i8_ty, 32)
ctx_alloca: llvmlite.Value* = llvmlite.build_alloca(wb, ctx_ty)
ctx_ptr: llvmlite.Value* = llvmlite.build_bitcast(wb, ctx_alloca, i8_ptr_ty)
# 2. 打包函数参数到结构体 {param_types}(装饰器可读写 args_ptr)
args_alloca: llvmlite.Value* = None
args_ptr: llvmlite.Value* = None
if n_params > 0:
fields_head: llvmlite.ParamNode* = None
fk: int = 0
for fk in range(n_params - 1, -1, -1):
pn_n: llvmlite.ParamNode* = llvmlite.new_param_node(pool, (llvmlite.LLVMType*)(param_tys[fk]))
if pn_n is not None:
pn_n.Next = fields_head
fields_head = pn_n
args_ty: llvmlite.LLVMType* = llvmlite.Struct(pool, fields_head, n_params, None)
if args_ty is not None:
args_alloca = llvmlite.build_alloca(wb, args_ty)
fi2: int = 0
for fi2 in range(n_params):
fld_ty: llvmlite.LLVMType* = (llvmlite.LLVMType*)(param_tys[fi2])
fld_ptr: llvmlite.Value* = llvmlite.build_gep_struct(wb, args_ty, fld_ty, args_alloca, fi2)
if fld_ptr is not None:
fld_nm: str = pool.alloc(16)
if fld_nm is not None:
viperlib.snprintf(fld_nm, 16, "%%a%d", fi2)
fld_v: llvmlite.Value* = llvmlite.SSAValue(pool, fld_ty, fld_nm)
if fld_v is not None:
llvmlite.build_store(wb, fld_v, fld_ptr)
args_ptr = llvmlite.build_bitcast(wb, args_alloca, i8_ptr_ty)
else:
args_ptr = llvmlite.ConstNull(pool, i8_ptr_ty, "null")
# 3. 返回值存储(零初始化;跳过原函数时返回安全默认值)
ret_alloca: llvmlite.Value* = None
if ret_is_void == 0:
ret_alloca = llvmlite.build_alloca(wb, ret_ty)
ret_zero: llvmlite.Value* = None
match ret_ty:
case llvmlite.LLVMType.Int(_):
ret_zero = llvmlite.ConstInt(pool, ret_ty, 0, "0")
case llvmlite.LLVMType.Float(_):
ret_zero = llvmlite.ConstFloat(pool, ret_ty, 0.0)
case _:
ret_zero = llvmlite.ConstNull(pool, ret_ty, "null")
if ret_zero is not None and ret_alloca is not None:
llvmlite.build_store(wb, ret_zero, ret_alloca)
# 4. 函数名字符串常量
fn_str: llvmlite.Value* = self.Gen.ExprGenConst.create_global_string(wb, pool, mod, func_name, trans)
if fn_str is None:
fn_str = llvmlite.ConstNull(pool, i8_ptr_ty, "null")
# 5. handler 声明(未翻译时 declare,固定签名 i32 (i8*,i8*,i32,i8*,i8*,i8*))
if self.Gen.CallGenBase.find_func_in_module(mod, handler_name) is None:
handler_d: llvmlite.Function* = llvmlite.create_declare(pool, mod, handler_name, i32_ty)
if handler_d is not None:
llvmlite.add_param(pool, handler_d, i8_ptr_ty, "ctx")
llvmlite.add_param(pool, handler_d, i8_ptr_ty, "func_name")
llvmlite.add_param(pool, handler_d, i32_ty, "phase")
llvmlite.add_param(pool, handler_d, i8_ptr_ty, "args_ptr")
llvmlite.add_param(pool, handler_d, i8_ptr_ty, "ret_ptr")
llvmlite.add_param(pool, handler_d, i8_ptr_ty, "decor_args_ptr")
# 6. 前置阶段:handler 返回调用次数 n_calls
ph0: llvmlite.Value* = llvmlite.ConstInt(pool, i32_ty, 0, "0")
null_ret: llvmlite.Value* = llvmlite.ConstNull(pool, i8_ptr_ty, "null")
null_dec: llvmlite.Value* = llvmlite.ConstNull(pool, i8_ptr_ty, "null")
# 参数链表(6 个独立值):ctx_ptr → fn_str → 0 → args_ptr → null → null
# 注意:不能 self 链接(null.Next = null 会让 build_call 遍历死循环)
if ctx_ptr is not None: llvmlite.value_set_next(ctx_ptr, fn_str)
if fn_str is not None: llvmlite.value_set_next(fn_str, ph0)
if ph0 is not None: llvmlite.value_set_next(ph0, args_ptr)
if args_ptr is not None: llvmlite.value_set_next(args_ptr, null_ret)
if null_ret is not None: llvmlite.value_set_next(null_ret, null_dec)
n_calls: llvmlite.Value* = llvmlite.build_call(wb, handler_name, ctx_ptr, 6, i32_ty, 0)
# 7. 计数器 alloca(TPV 用 alloca 计数器替代 phi)
cnt_alloca: llvmlite.Value* = llvmlite.build_alloca(wb, i32_ty)
cnt_zero: llvmlite.Value* = llvmlite.ConstInt(pool, i32_ty, 0, "0")
if cnt_alloca is not None and cnt_zero is not None:
llvmlite.build_store(wb, cnt_zero, cnt_alloca)
llvmlite.build_br(wb, loop_h_bb)
# 8. loop.header:cur = load cnt; cur < n_calls → body / post
llvmlite.position_at_end(wb, loop_h_bb)
cur_i: llvmlite.Value* = llvmlite.build_load(wb, i32_ty, cnt_alloca)
loop_cond: llvmlite.Value* = llvmlite.build_icmp(wb, llvmlite.ICMP_SLT, cur_i, n_calls)
llvmlite.build_cond_br(wb, loop_cond, loop_b_bb, post_bb)
# 9. loop.body:读回参数(装饰器可能已修改)→ 调用原函数 → store ret
llvmlite.position_at_end(wb, loop_b_bb)
call_args: llvmlite.Value* = None
if n_params > 0:
k: int = 0
for k in range(n_params):
fld_ty_k: llvmlite.LLVMType* = (llvmlite.LLVMType*)(param_tys[k])
fld_pk: llvmlite.Value* = llvmlite.build_gep_struct(wb, args_ty, fld_ty_k, args_alloca, k)
if fld_pk is None: continue
fld_vk: llvmlite.Value* = llvmlite.build_load(wb, fld_ty_k, fld_pk)
if fld_vk is not None:
llvmlite.value_set_next(fld_vk, None)
if call_args is None:
call_args = fld_vk
else:
ct: llvmlite.Value* = call_args
while ct.Next is not None:
ct = ct.Next
llvmlite.value_set_next(ct, fld_vk)
res_v: llvmlite.Value* = llvmlite.build_call(wb, orig_call_name, call_args, n_params, ret_ty, 0)
if ret_alloca is not None and res_v is not None:
llvmlite.build_store(wb, res_v, ret_alloca)
nxt_i: llvmlite.Value* = llvmlite.build_add(wb, cur_i, llvmlite.ConstInt(pool, i32_ty, 1, "1"))
if nxt_i is not None and cnt_alloca is not None:
llvmlite.build_store(wb, nxt_i, cnt_alloca)
llvmlite.build_br(wb, loop_h_bb)
# 10. post:handler 后置 → 清递归标志 → 返回结果
llvmlite.position_at_end(wb, post_bb)
ret_ptr: llvmlite.Value* = null_ret
if ret_alloca is not None:
ret_ptr = llvmlite.build_bitcast(wb, ret_alloca, i8_ptr_ty)
ph1: llvmlite.Value* = llvmlite.ConstInt(pool, i32_ty, 1, "1")
# 后置参数链:ctx_ptr → fn_str → 1 → args_ptr → ret_ptr → null
if ctx_ptr is not None: llvmlite.value_set_next(ctx_ptr, fn_str)
if fn_str is not None: llvmlite.value_set_next(fn_str, ph1)
if ph1 is not None: llvmlite.value_set_next(ph1, args_ptr)
if args_ptr is not None: llvmlite.value_set_next(args_ptr, ret_ptr)
if ret_ptr is not None: llvmlite.value_set_next(ret_ptr, null_dec)
llvmlite.build_call(wb, handler_name, ctx_ptr, 6, i32_ty, 0)
if rec_flag_ref is not None:
rec_zero2: llvmlite.Value* = llvmlite.ConstInt(pool, i8_ty, 0, "0")
if rec_zero2 is not None:
llvmlite.build_store(wb, rec_zero2, rec_flag_ref)
if ret_is_void != 0:
llvmlite.build_ret_void(wb)
else:
final_v: llvmlite.Value* = llvmlite.build_load(wb, ret_ty, ret_alloca)
if final_v is not None:
llvmlite.build_ret(wb, final_v)
else:
llvmlite.build_ret_void(wb)
return wrapper