fix(tpc): 函数声明创建收口到幂等入口 _CreateOrReuseFuncDecl;清理 DDEBUG 探针

类别:a 编译器缺陷(根因修复)+ 调试探针移除。

现场:翻译 CallGenFd.vp 时抛 llvmlite.ir._utils.DuplicatedNameError:
'5d84ea579d83ef73.CallGenFd._translate_fakeduck_call'(llvmlite 的
NameScope 按名字去重,GlobalValue.deduplicate_name=False ⇒ 同名 global
建第二次必抛,且报文只给名字、不给两侧签名)。

根因:BaseGen._get_or_declare_function 建完 ir.Function 后**只加入
module.globals**(llvmlite 自动)而**未登记 Gen.functions**;而
HandlesFunctions._EmitFunctionLlvm 的 need_new 判据只看 Gen.functions
(`MangledName not in Gen.functions`)⇒ 同一名字再建一次 → DuplicatedNameError;
该处 except 又把它吞掉(非 strict 模式只 LogWarning)→ 函数始终没进
Gen.functions → 后续其它创建点(FuncGen._get_or_declare_func /
get_or_declare_c_func,同样只查 self.functions)再建 → 异常从别处逃逸到
Phase2Translator。

修复:
1. BaseGen 新增 _CreateOrReuseFuncDecl(name, func_type) —— 函数声明创建的
   唯一幂等入口:module.globals 已有同名函数且**函数类型结构串相同**则复用
   (并补登记 Gen.functions;FunctionType 无 __eq__,只能比 str);
   类型不同则 fail-fast 报出两侧签名(declare/define 分裂的真因),
   绝不静默复用错签名(调用点会按错签名传参)。
2. _get_or_declare_function 改走该入口(顺带补登记 Gen.functions);
   FuncGen._get_or_declare_func / get_or_declare_c_func 改走该入口;
   HandlesFunctions 定义路径改走该入口,且该处 except 对 FailFastError
   直接 re-raise(不再吞)。
3. 清理遗留调试探针(含 sys.exit(1)):BaseGen 三处 [DDEBUG]
   (_get_or_declare_function 双点 / _mangle_func_name 前导点与结果双点)、
   HandlesExprAsm 两处 [DDEBUG_ASM]、HandlesExprCall 一处
   [DDEBUG] _HandleClosureCallLlvm。
This commit is contained in:
TermiNexus committed 2026-09-29 13:00:11 +08:00
1 parent 3bc3c48dee
commit 9d8aedec4a
5 files changed
+47 -57

No files matched your search

-10
View File
@@ -310,11 +310,6 @@ class ExprAsmHandle(BaseHandle):
def _mangle_asm_calls(self, template: str) -> str:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
sha1: str = getattr(Gen, 'module_sha1', '')
# DDEBUG: 检测 module_sha1 是否带尾随点(双点 bug 根因拦截)
if sha1 and sha1.endswith('.'):
import sys as _dbg_sys
print(f"[DDEBUG_ASM] module_sha1 带尾随点: sha1='{sha1}' len={len(sha1)} template='{template[:80]}'", file=_dbg_sys.stderr)
_dbg_sys.exit(1)
if not sha1:
return template
@@ -324,11 +319,6 @@ class ExprAsmHandle(BaseHandle):
if func_name.lower() in self._X86_REGISTERS:
return m.group(0)
mangled: str = Gen._mangle_func_name(func_name)
# DDEBUG: 检测 mangled 是否含双点(双点 bug 根因拦截)
if '..' in mangled:
import sys as _dbg_sys
print(f"[DDEBUG_ASM] mangled 含双点: func='{func_name}' mangled='{mangled}' sha1='{sha1}'", file=_dbg_sys.stderr)
_dbg_sys.exit(1)
if '.' in mangled:
return f'{prefix}\\22{mangled}\\22'
return f"{prefix}{mangled}"
-9
View File
@@ -2479,15 +2479,6 @@ class ExprCallHandle(BaseHandle):
def _HandleClosureCallLlvm(self, Node: ast.Call, FuncName: str) -> ir.Value:
Gen = self.Trans.LlvmGen
func = Gen.functions.get(FuncName)
# DDEBUG: 检测 func.name 含双点(说明 ir.Function 已被错误注册为双点名字)
if func is not None and '..' in getattr(func, 'name', ''):
import sys
sys.stderr.write(f"[DDEBUG] _HandleClosureCallLlvm DOUBLE-DOT func.name='{func.name}' FuncName='{FuncName}'\n")
sys.stderr.write(f"[DDEBUG] Gen.functions keys for '{FuncName}': {[k for k in list(Gen.functions.keys()) if '6ddf' in k or k == FuncName][:20]}\n")
import traceback
traceback.print_stack(file=sys.stderr, limit=10)
sys.stderr.flush()
sys.exit(1)
if not func:
if FuncName in self.Trans.FunctionDefCache:
FuncDef = self.Trans.FunctionDefCache[FuncName]
+11 -1
View File
@@ -1253,7 +1253,13 @@ class FunctionHandle(BaseHandle):
need_new = True
if need_new:
try:
func: ir.Function = ir.Function(Gen.module, FuncType, name=MangledName)
# 统一走幂等入口:module.globals 已有同名函数时复用(并补登记
# Gen.functions),签名冲突则 fail-fast —— 绝不直接新建同名
# ir.Function(llvmlite NameScope 按名去重,必抛 DuplicatedNameError;
# 现场:5d84ea579d83ef73.CallGenFd._translate_fakeduck_call 被此路径新建,
# 而 BaseGen._get_or_declare_function 已建过同名声明却未登记
# Gen.functions ⇒ need_new 误判为真)。
func: ir.Function = Gen._CreateOrReuseFuncDecl(MangledName, FuncType)
func.attributes.add('noredzone')
if hasattr(self, '_cdefine_funcs') and FuncName in self._cdefine_funcs:
func.linkage = 'linkonce_odr'
@@ -1270,6 +1276,10 @@ class FunctionHandle(BaseHandle):
if MangledName == FuncName or FuncName not in Gen._export_extern_funcs:
Gen.functions[FuncName] = func
except Exception as _e:
from lib.core.LLVMCG.FuncGen import FailFastError
if isinstance(_e, FailFastError):
# 签名冲突 = declare/define 分裂,必须终止(不吞)
raise
if _config_mode == "strict":
self.Trans.LogWarning(f"异常被忽略: {_e}")
else:
+30 -28
View File
@@ -871,33 +871,43 @@ class BaseGenMixin:
return [p]
return []
def _CreateOrReuseFuncDecl(self, name: str, func_type: ir.FunctionType) -> ir.Function:
"""函数声明创建的唯一幂等入口(所有"新建 ir.Function"的路径都应走这里)。
llvmlite 的 NameScope 按名字去重(GlobalValue.deduplicate_name=False):
同名 global 再建一次必抛 llvmlite.ir._utils.DuplicatedNameError(只给名字、
不给两侧签名,现场:5d84ea579d83ef73.CallGenFd._translate_fakeduck_call)。
故此处:
· module.globals 已有同名函数且函数类型(按字符串比较,FunctionType 无
__eq__ ⇒ 只能比结构串)相同 ⇒ **复用**并补登记 Gen.functions;
· 已有但类型不同 ⇒ fail-fast 报出两侧签名 —— 这是 declare / define 分裂的
真因,绝不静默复用错签名(会让调用点按错签名传参)。
"""
existing: Any = self.module.globals.get(name)
if isinstance(existing, ir.Function):
_old_type: Any = getattr(existing, 'ftype', None)
if _old_type is None or str(_old_type) == str(func_type):
self.functions[name] = existing
return existing
from lib.core.LLVMCG.FuncGen import FailFastError
raise FailFastError(
f"同名函数声明签名冲突(declare/define 分裂):'{name}'"
f"\n · 已存在声明: {_old_type}"
f"\n · 本次要创建: {func_type}"
f"\n 拒绝静默复用(调用点会按错签名传参);请核对同一函数在声明侧"
f"(stub / .vpi)与定义侧的注解解析结果是否一致。")
func: ir.Function = ir.Function(self.module, func_type, name=name)
self.functions[name] = func
return func
def _get_or_declare_function(self, mangled_name: str, func_type: ir.FunctionType) -> ir.Function:
# DDEBUG: 检测 mangled_name 含双点(不应到达这里)
if '..' in mangled_name:
import sys
sys.stderr.write(f"[DDEBUG] _get_or_declare_function DOUBLE-DOT mangled_name='{mangled_name}'\n")
import traceback
traceback.print_stack(file=sys.stderr, limit=10)
sys.stderr.flush()
sys.exit(1)
g = self.module.globals.get(mangled_name)
if g and isinstance(g, ir.Function):
return g
return ir.Function(self.module, func_type, name=mangled_name)
return self._CreateOrReuseFuncDecl(mangled_name, func_type)
def _get_function(self, name: str) -> ir.Function | None:
func: ir.Function | None = self._find_function(name)
return func
def _mangle_func_name(self, name: str, module_name: str | None = None) -> str:
# DDEBUG: 检测即将产生双点的情况,立即打印并终止
if name.startswith('.') or (module_name and module_name.endswith('.') and len(module_name) > 0):
import sys
sys.stderr.write(f"[DDEBUG] _mangle_func_name LEADING-DOT name='{name}' module_name='{module_name}'\n")
import traceback
traceback.print_stack(file=sys.stderr, limit=8)
sys.stderr.flush()
sys.exit(1)
if name in self._export_funcs and not module_name:
return name
if name in self._export_extern_funcs:
@@ -955,14 +965,6 @@ class BaseGenMixin:
result = f"{self.module_sha1}.{name}"
else:
result = name
# DDEBUG: 检测返回结果中是否含双点
if '..' in result:
import sys
sys.stderr.write(f"[DDEBUG] _mangle_func_name RESULT-DOUBLE-DOT name='{name}' module_name='{module_name}' result='{result}'\n")
import traceback
traceback.print_stack(file=sys.stderr, limit=10)
sys.stderr.flush()
sys.exit(1)
return result
def _get_source_line(self, lineno: int) -> str | None:
+6 -9
View File
@@ -812,9 +812,10 @@ class FuncGenMixin:
return fobj
if re.match(r'^[0-9a-f]{16,}\.' + re.escape(name) + r'$', fname):
return fobj
func_decl: ir.Function = ir.Function(self.module, func_type, name=name)
self.functions[name] = func_decl
return func_decl
# module.globals 里可能已有同名函数而 Gen.functions 未登记(如
# BaseGen._get_or_declare_function 的历史路径):直接新建必抛 llvmlite
# DuplicatedNameError(NameScope 按名去重)⇒ 统一走幂等入口。
return self._CreateOrReuseFuncDecl(name, func_type)
def get_or_declare_c_func(self, name: str, fallback_type: ir.FunctionType | None = None) -> ir.Function | None:
if name in self.functions:
@@ -831,11 +832,7 @@ class FuncGenMixin:
raise
_vlog().warning(f"查找桩函数类型失败: {_e}", "Exception")
if stub_func_type:
func_decl: ir.Function = ir.Function(self.module, stub_func_type, name=name)
self.functions[name] = func_decl
return func_decl
return self._CreateOrReuseFuncDecl(name, stub_func_type)
if fallback_type is not None:
func_decl: ir.Function = ir.Function(self.module, fallback_type, name=name)
self.functions[name] = func_decl
return func_decl
return self._CreateOrReuseFuncDecl(name, fallback_type)
return None