Files
ViperC/App/lib/core/Gen/FuncGenDef.vp
T
TermiNexus 89995dffde refactor(gen): 去除 Handles 委托层——链式化 + GenTypes/GenApi 迁移
- Gen 内部 1742 处 HandlesX.func() 改 self.Gen.Y.method() 链式调用
- 数据类/常量迁移 GenTypes.vp(10 类 + CLASS_META_*/META_*/SEQ_KIND_*/FIELD_MAX 等)
- 管线/保留文件经 GenApi.vp 模块级入口(48 函数带类型注解,从 Gen 方法签名自动生成)
- 删除 26 个纯委托 Handles 文件,仅留 5 个实体文件(Base/Translator/Expr/ExprCall/ExprCallTable)
- 修复字段分裂:TypeGenErr CurrentFile/TraceCount 链式化;CallGenBase TempDir/Cexport 真源化
2026-08-21 06:32:40 +08:00

1232 lines
72 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 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.Handles.HandlesTranslator as HT
import lib.core.Handles.HandlesExpr as HandlesExpr
import lib.core.Handles.HandlesExprCall as HandlesExprCall
import lib.core.Handles.ExprCallTable as ExprCallTable
# ============================================================
# FuncGenDef - FuncGenMixin 拆分(阶段 D):函数声明 / translate_function_def / decorator wrapper
#
# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。
# 跨 Mixin 调用统一走 HandlesExprCall 委托(经 _g_gen)。
# @t.NoVTable:静态绑定。
# ============================================================
@t.NoVTable
class FuncGenDef(CallGenBase.CallGenBase):
"""函数声明 / translate_function_def / decorator wrapper"""
# ============================================================
# forward_declare_functions - 预扫描所有顶层 FunctionDef,创建前向声明
#
# 解决同模块内前向引用问题:如 viperlib.py 中 sprintf(行15) 调用
# vsnprintf(行41),但 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 | t.CPtr,
tree: ast.AST | t.CPtr) -> int:
"""预扫描所有顶层 FunctionDef,创建前向声明"""
if trans is None or tree is None:
return 0
pool: memhub.MemBuddy | t.CPtr = trans.Pool
mod: llvmlite.LLVMModule | t.CPtr = 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 | t.CPtr = trans._funcs
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
ch: list[ast.AST | t.CPtr] | t.CPtr = 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: t.CSizeT = len(ch)
for ci in range(cn_count):
child: ast.AST | t.CPtr = ch.get(ci)
if child is None:
continue
if child.kind() != ast.ASTKind.FunctionDef:
continue
fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(child)
if fd is None or fd.name is None:
continue
# 推断返回类型
ret_ty: llvmlite.LLVMType | t.CPtr = None
if fd.returns is not None:
ret_ty = self.Gen.TypeGenResolve.resolve_annotation_type(
pool, fd.returns, imported_modules, from_imports, trans)
if ret_ty is None and fd.returns is not None:
if self.Gen.TypeGenErr.has_decorator_marker(fd.returns, "State") != 0:
ret_ty = llvmlite.Void(pool)
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")
has_state = self.Gen.TypeGenErr.has_decorator_marker(fd.returns, "State")
has_export = self.Gen.TypeGenErr.has_decorator_marker(fd.returns, "CExport")
# 装饰器形式存储类标记(@t.CExport/@t.CExtern/@t.State/@t.CStatic)
# 对齐 TPC HandlesFunctions._extract_decorator_storage_flags;
# CExport/CExtern/State 影响函数名(导出裸名),CStatic 仅标记。
# 注意: 用 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
# 计算 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 | t.CPtr = self.Gen.CallGenBase.find_func_in_module(mod, mangled_name)
if existing is not None:
continue
# 创建 declare
func: llvmlite.Function | t.CPtr = llvmlite.create_declare(
pool, mod, mangled_name, ret_ty)
if func is None:
continue
# 提取默认参数信息
# 注意: 必须先把属性赋给显式类型为 list[...] | t.CPtr 的局部变量再调用 __len__(),
# 否则编译器无法识别属性返回的 list 类型,GEP base 会变成 i32 0 导致 llc 报错
fd_args_node: ast.Arguments | t.CPtr = fd.args
fd_defaults: t.CVoid | t.CPtr = None
fd_default_count: int = 0
fd_param_count: int = 0
if fd_args_node is not None:
fd_ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(fd_args_node)
if fd_ags.args is not None:
fd_alist: list[ast.AST | t.CPtr] | t.CPtr = fd_ags.args
fd_param_count = len(fd_alist)
if fd_ags.defaults is not None:
fd_dlist: list[ast.AST | t.CPtr] | t.CPtr = 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 | t.CPtr = fd.args
if args_node is not None:
ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node)
if ags.args is not None:
alist: list[ast.AST | t.CPtr] | t.CPtr = ags.args
an: t.CSizeT = len(alist)
for ai in range(an):
arg: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist.get(ai))
if arg is None or arg.arg is None:
continue
# t.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 | t.CPtr = i32_ty
if arg.annotation is not None:
resolved: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.resolve_annotation_type(
pool, arg.annotation, imported_modules, from_imports, trans)
if resolved is not None:
# 裸类形参 → Ptr(struct)(对象即指针,与方法形参一致)
# CArray 形参 → 元素指针 ty*(C 数组衰减,与 add_param 一致)
match resolved:
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
# 参数添加完成,补全全局函数表的 TypeStr(供 vtable 在 func 被 reset 后使用)
self.Gen.CallGenLeafKit.update_global_func_typestr(trans.Pool, fd.name, func)
# 恢复原始声明模式
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 | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""翻译函数定义,返回新增的变量数(通常为 0,函数定义不增加当前作用域变量)"""
fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(node)
if fd is None or fd.name is None:
return 0
pool: memhub.MemBuddy | t.CPtr = trans.Pool
mod: llvmlite.LLVMModule | t.CPtr = trans.Module
imported_modules: str = trans._imported_modules
from_imports: str = trans._from_imports
funcs_ptr: GenTypes.FuncEntry | t.CPtr = trans._funcs
func_count: int = trans._func_count
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
# 推断返回类型:优先使用返回类型注解
ret_ty: llvmlite.LLVMType | t.CPtr = None
if fd.returns is not None:
ret_ty = self.Gen.TypeGenResolve.resolve_annotation_type(
pool, fd.returns, imported_modules, from_imports, trans)
# 如果返回类型注解纯装饰器标记(如 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:
ret_ty = llvmlite.Void(pool)
# 如果仍然为 None,扫描 return 语句推断(至少返回 i32)
if ret_ty is None:
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")
has_state = self.Gen.TypeGenErr.has_decorator_marker(fd.returns, "State")
has_export = self.Gen.TypeGenErr.has_decorator_marker(fd.returns, "CExport")
# 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: t.CInt64T = 0
if fd.decorator_list is not None:
ddn: t.CSizeT = len(fd.decorator_list)
for ddi in range(ddn):
deco: ast.AST | t.CPtr = 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 | t.CPtr = (ast.Name | t.CPtr)(deco)
dname = dnm.id
elif dk == ast.ASTKind.Call:
dcl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(deco)
if dcl.func is not None and dcl.func.kind() == ast.ASTKind.Name:
dnm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(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 | t.CPtr = dcl.args.get(0)
if da0 is not None and da0.kind() == ast.ASTKind.Constant:
dc0: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(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 | t.CPtr = self.Gen.CallGenBase.find_func_in_module(mod, mangled_name)
if existing_extern is not None:
# 已存在前向声明,复用之,不再重复创建
return 0
func: llvmlite.Function | t.CPtr = 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 | t.CPtr = fd.args
if args_node_extern is not None:
ags_e: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node_extern)
if ags_e.args is not None:
alist_e: list[ast.AST | t.CPtr] | t.CPtr = ags_e.args
an_e: t.CSizeT = len(alist_e)
for ai_e in range(an_e):
arg_e: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist_e.get(ai_e))
if arg_e is not None and arg_e.arg is not None:
# t.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 | t.CPtr = i32_ty
if arg_e.annotation is not None:
resolved_e: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.resolve_annotation_type(
pool, arg_e.annotation, imported_modules, from_imports, trans)
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 数组衰减)
match resolved_e:
case llvmlite.LLVMType.Struct(_, _, _):
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)
# 参数添加完成,补全全局函数表的 TypeStr
self.Gen.CallGenLeafKit.update_global_func_typestr(pool, fd.name, func)
return 0
# args_node 用于后续 alloca 创建,提前赋值
args_node: ast.Arguments | t.CPtr = fd.args
# 检查是否已有前向声明(由 forward_declare_functions 创建)
func: llvmlite.Function | t.CPtr = 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)
else:
# 创建新的 LLVM 函数(使用 SHA1 混淆名)
func = llvmlite.create_function(pool, mod, mangled_name, ret_ty)
if func is None:
fb_cf: str = VLogger.fmt_buf()
if fb_cf is not None:
viperlib.snprintf(fb_cf, 1024, "create_function %s failed", fd.name)
VLogger.error(fb_cf, "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)
# 提取默认参数信息
tfd_defaults: t.CVoid | t.CPtr = None
tfd_default_count: int = 0
tfd_param_count: int = 0
if args_node is not None:
tfd_ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node)
if tfd_ags.args is not None:
tfd_alist: list[ast.AST | t.CPtr] | t.CPtr = tfd_ags.args
tfd_param_count = len(tfd_alist)
if tfd_ags.defaults is not None:
tfd_dlist: list[ast.AST | t.CPtr] | t.CPtr = 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 | t.CPtr = (ast.Arguments | t.CPtr)(args_node)
if ags.args is not None:
alist: list[ast.AST | t.CPtr] | t.CPtr = ags.args
an: t.CSizeT = len(alist)
for ai in range(an):
arg: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist.get(ai))
if arg is not None and arg.arg is not None:
# t.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 | t.CPtr = i32_ty
if arg.annotation is not None:
resolved: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.resolve_annotation_type(
pool, arg.annotation, imported_modules, from_imports, trans)
if resolved is not None:
# 裸类形参 → Ptr(struct)(对象即指针,与方法形参一致)
# CArray 形参 → 元素指针 ty*(C 数组衰减:final(out: t.CArray[..., N])
# 的 out 指向调用方数组首元素;传 Ptr(数组) 会使 out[i] 的
# GEP 以整个数组为步长错位,摘要垃圾根因)
match resolved:
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 | t.CPtr = llvmlite.Int8(pool)
i8_ptr_ty_eh: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_eh)
i8_ptr_ptr_ty_eh: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty_eh)
i32_ty_eh: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
i32_ptr_ty_eh: llvmlite.LLVMType | t.CPtr = 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__")
# 参数添加完成,补全全局函数表的 TypeStr
self.Gen.CallGenLeafKit.update_global_func_typestr(trans.Pool, fd.name, func)
# 创建 entry 块
entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, "entry")
if entry_blk is None:
return 0
# 创建函数专属 builder
func_builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, func)
if func_builder is None:
return 0
llvmlite.position_at_end(func_builder, entry_blk)
# @t.TLS 一次性初始化守卫(对齐 TPC HandlesFunctions.py L1763-1792):
# 首次调用执行函数体并置全局标志 __tls_init_done_{name}=1,后续调用
# 直接返回默认值。TPV 此前未实现 @t.TLS,_init_tls 每次 TlsAlloc 导致
# provider 栈跨调用丢失(FakeDuckTest Test 9 注入失败根因)。
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 | t.CPtr = llvmlite.create_global_int(
pool, mod, tls_flag_name, 1, 0)
if tls_flag_gv is not None:
i1_ty_t: llvmlite.LLVMType | t.CPtr = 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 | t.CPtr = 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 | t.CPtr = llvmlite.SSAValue(
pool, tls_gv_ptr_ty, tls_ref_name)
if tls_flag_ref is not None:
tls_flag_ld: llvmlite.Value | t.CPtr = 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: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
pool, func, tls_bb_buf)
viperlib.snprintf(tls_bb_buf, 64, "tls.cont.%d", lc_t)
tls_cont_bb: llvmlite.BasicBlock | t.CPtr = 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 | t.CPtr = 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 | t.CPtr = llvmlite.ConstFloat(
pool, ret_ty, 0.0)
if tlf0 is not None:
llvmlite.build_ret(func_builder, tlf0)
case _:
tln0: llvmlite.Value | t.CPtr = 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 | t.CPtr = 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, SCOPE_FUNCTION)
# PEP 695 泛型函数: def f[T](...) — 设置泛型上下文,类型参数映射到 "int" 兜底。
# TPV 无泛型函数特化机制(类泛型走 _specialize_generic_class),泛型函数按普通
# 函数编译;设置上下文使参数注解 T / 方法体中的 T(x) 转换可解析为 int。
# (注意与类特化的 set_generic_context 一样是全局状态,需在退出作用域前清除。)
tp_names_fn: list[str] | t.CPtr = None
if fd.type_params is not None:
tp_names_fn = fd.type_params
tp_args_fn: list[str] | t.CPtr = list[str](pool, 8)
if tp_args_fn is not None:
tpn_fn: t.CSizeT = len(fd.type_params)
tpi_fn: t.CSizeT = 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 | t.CPtr = (ast.Arguments | t.CPtr)(args_node)
if ags2.args is not None:
alist2: list[ast.AST | t.CPtr] | t.CPtr = ags2.args
an2: t.CSizeT = len(alist2)
for ai2 in range(an2):
arg2: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist2.get(ai2))
if arg2 is not None and arg2.arg is not None:
# t.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 | t.CPtr = i32_ty
if arg2.annotation is not None:
resolved2: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.resolve_annotation_type(
pool, arg2.annotation, imported_modules, from_imports, trans)
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.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 | t.CPtr = 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)
if cls_nm is not None:
self.Gen.VarGen.set_var_annot_class_name(
trans.SymTab, arg2.arg, cls_nm)
pname2: str = pool.alloc(32)
if pname2 is not None:
viperlib.snprintf(pname2, 32, "%%%s", arg2.arg)
param_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(
pool, param_ty2, pname2)
llvmlite.build_store(func_builder, param_val, alloca)
# *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 | t.CPtr = (ast.Arg | t.CPtr)(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 | t.CPtr = llvmlite.Int8(pool)
i8_ptr_ty_va: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_va)
va_buf_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Array(pool, i8_ty_va, 24)
va_list_alloca: llvmlite.Value | t.CPtr = 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 | t.CPtr = 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 | t.CPtr = 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 | t.CPtr = trans._eh_msg_out_param
old_eh_code_out: llvmlite.Value | t.CPtr = 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 | t.CPtr = llvmlite.Int8(pool)
i8_ptr_ty_eh2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_eh2)
i8_ptr_ptr_ty_eh2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty_eh2)
i32_ty_eh2: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
i32_ptr_ty_eh2: llvmlite.LLVMType | t.CPtr = 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 | t.CPtr = llvmlite.SSAValue(
pool, i8_ptr_ptr_ty_eh2, "%__eh_msg_out__")
code_out_ref: llvmlite.Value | t.CPtr = 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 | t.CPtr = trans._cur_func
old_builder: llvmlite.IRBuilder | t.CPtr = 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 | t.CPtr = trans._va_list_ptr
old_vararg_name: str = trans._vararg_name
trans._cur_func = func
trans._cur_builder = func_builder
# 清空 global/nonlocal 名称集合(新函数作用域)
HT.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 | t.CPtr] | t.CPtr = fd.children
if body is not None:
bn: t.CSizeT = len(body)
for bi in range(bn):
stmt: ast.AST | t.CPtr = 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 | t.CPtr = body.get(bi)
if stmt is not None:
self.Gen.StmtGenDecl.pre_scan_allocas(trans, stmt)
# 翻译函数体
if body is not None:
bn2: t.CSizeT = len(body)
for bi2 in range(bn2):
stmt2: ast.AST | t.CPtr = 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: t.CSizeT = 0
if body is not None:
bn3 = len(body)
if bn3 > 0:
last_stmt: ast.AST | t.CPtr = 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:
# 追加89:编译器不替代码发明返回值——函数流程真实掉出末尾而
# 未显式 return 时 fail-fast(要求补 return,Python traceback
# 风格定位到函数)。三种合法收尾:
# ① void 函数掉出末尾 → ret void(无值可发明,Python 语义)
# ② 末句是控制流语句(match/if 全分支 return)且当前块
# 未 terminated → merge 块结构性不可达 → unreachable
# ③ 无返回类型注解的函数(fd.returns is None,如
# ast/base.vp _set_pos 过程风格赋值函数)→ 视为无返回值
# 函数,默认生成零值返回(用户决策:没有返回值默认不用
# return;ConstZero 按推断出的 ret_ty 构造,类型匹配)
# 有 -> 注解且末句是普通语句掉出末尾 → fail-fast(不得替代码
# 发明返回值,也不做 noreturn 函数名白名单——错误终止路径
# 也必须在源码层面保证块收尾,如显式 return 样板)
# 末句是否为控制流语句(If/Match/While/For/Try/With):
# 控制流语句翻译后当前块未 terminated 表示 merge 块结构性
# 不可达(所有分支均已 return/terminated)——对非 void 函数
# 生成 unreachable 而非 fail-fast(GCC/Clang 对 fall-through
# 视为 UB 同语义;追加89 修正 get_struct_name 全 case return
# 被错判"不可能抵达")
last_is_ctrl: int = 0
if bn3 > 0:
last_stmt3: ast.AST | t.CPtr = 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
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 使 llc
# O2 把 br-to-unreachable 优化为 fall-through → 双分支执行
# 崩溃(FuncTest check PASS+FAIL 双打印)
llvmlite.build_unreachable(func_builder)
elif fd.returns is None:
# 无返回类型注解 → 无返回值过程函数,默认零值返回
if ret_ty is not None:
zero_val: llvmlite.Value | t.CPtr = 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
# 恢复外层函数(调用方)的 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)
return 0
# ============================================================
# _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 | t.CPtr,
pool: memhub.MemBuddy | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
func: llvmlite.Function | t.CPtr,
func_name: str,
wrapper_name: str,
handler_name: str,
decor_arg0: t.CInt64T) -> llvmlite.Function | t.CPtr:
"""生成装饰器 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 | t.CPtr = 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 | t.CPtr = llvmlite.Int32(pool)
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
# ---- 收集原函数参数类型(按位置,最多 16 个)----
n_params: int = 0
param_tys: t.CSizeT | t.CPtr = pool.alloc(16 * 8)
if param_tys is None:
return None
string.memset(param_tys, 0, 16 * 8)
pp: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(func)
while pp is not None:
pty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(pp)
if pty is not None and n_params < 16:
param_tys[n_params] = t.CSizeT(pty)
n_params += 1
pp = llvmlite.param_get_next(pp)
# ---- 创建 wrapper 函数并添加参数(名字 %a0..%aN)----
wrapper: llvmlite.Function | t.CPtr = 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 | t.CPtr)(
t.CVoid(param_tys[pi], t.CPtr)), pname_w)
# ---- 创建块 ----
entry_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, wrapper, "entry")
loop_h_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, wrapper, "loop.header")
loop_b_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, wrapper, "loop.body")
post_bb: llvmlite.BasicBlock | t.CPtr = 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 | t.CPtr = 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 | t.CPtr = 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: llvmlite.BasicBlock | t.CPtr = entry_bb
if rec_flag_ref is not None:
rec_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, wrapper, "recursive_call")
dec_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, wrapper, "decorated_entry")
if rec_bb is None or dec_bb is None:
return None
rec_val: llvmlite.Value | t.CPtr = llvmlite.build_load(wb, i8_ty, rec_flag_ref)
rec_zero: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i8_ty, 0, "0")
rec_is: llvmlite.Value | t.CPtr = 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 | t.CPtr = 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 | t.CPtr = llvmlite.SSAValue(
pool, (llvmlite.LLVMType | t.CPtr)(t.CVoid(param_tys[ri], t.CPtr)), 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 | t.CPtr = 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 | t.CPtr = 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 | t.CPtr = 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 | t.CPtr = llvmlite.Array(pool, i8_ty, 32)
ctx_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(wb, ctx_ty)
ctx_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(wb, ctx_alloca, i8_ptr_ty)
# 2. 打包函数参数到结构体 {param_types}(装饰器可读写 args_ptr)
args_alloca: llvmlite.Value | t.CPtr = None
args_ptr: llvmlite.Value | t.CPtr = None
if n_params > 0:
fields_head: llvmlite.ParamNode | t.CPtr = None
fk: int = 0
for fk in range(n_params - 1, -1, -1):
pn_n: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(
pool, (llvmlite.LLVMType | t.CPtr)(t.CVoid(param_tys[fk], t.CPtr)))
if pn_n is not None:
pn_n.Next = fields_head
fields_head = pn_n
args_ty: llvmlite.LLVMType | t.CPtr = 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 | t.CPtr = (llvmlite.LLVMType | t.CPtr)(
t.CVoid(param_tys[fi2], t.CPtr))
fld_ptr: llvmlite.Value | t.CPtr = 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 | t.CPtr = 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 | t.CPtr = None
if ret_is_void == 0:
ret_alloca = llvmlite.build_alloca(wb, ret_ty)
ret_zero: llvmlite.Value | t.CPtr = 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 | t.CPtr = 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 | t.CPtr = 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 | t.CPtr = llvmlite.ConstInt(pool, i32_ty, 0, "0")
null_ret: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, i8_ptr_ty, "null")
null_dec: llvmlite.Value | t.CPtr = 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 | t.CPtr = llvmlite.build_call(
wb, handler_name, ctx_ptr, 6, i32_ty, 0)
# 7. 计数器 alloca(TPV 用 alloca 计数器替代 phi)
cnt_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(wb, i32_ty)
cnt_zero: llvmlite.Value | t.CPtr = 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 | t.CPtr = llvmlite.build_load(wb, i32_ty, cnt_alloca)
loop_cond: llvmlite.Value | t.CPtr = 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 | t.CPtr = None
if n_params > 0:
k: int = 0
for k in range(n_params):
fld_ty_k: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(
t.CVoid(param_tys[k], t.CPtr))
fld_pk: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
wb, args_ty, fld_ty_k, args_alloca, k)
if fld_pk is None:
continue
fld_vk: llvmlite.Value | t.CPtr = 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 | t.CPtr = call_args
while ct.Next is not None:
ct = ct.Next
llvmlite.value_set_next(ct, fld_vk)
res_v: llvmlite.Value | t.CPtr = 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 | t.CPtr = 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 | t.CPtr = null_ret
if ret_alloca is not None:
ret_ptr = llvmlite.build_bitcast(wb, ret_alloca, i8_ptr_ty)
ph1: llvmlite.Value | t.CPtr = 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 | t.CPtr = 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 | t.CPtr = 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