feat(sidecar): 落盘 {sha1}.meta 函数定义清单,声明文件判定改读结构化 sidecar

- 新增 WriteModuleFuncMeta:翻译期从 Module.FuncHead + Function.IsDeclared 产出 FUNC <mangled> DEF|DECL(与 dump_ir 的 stub/text 判据同源)
- 新增 _MetaHasDef / 重写 IsDeclOnlyModule:不再扫 text.ll 的 define 行,改读 meta
- Phase1/Phase2 落盘点紧随 text.ll 写出 meta;Phase1 增量跳转额外要求 meta 存在
- Phase2 内联 is_decl_mi 与 PhaseC 判定统一走 IsDeclOnlyModule

去 IR 化步骤①(sidecar 最小闭环),全后端统一,默认行为不变。
This commit is contained in:
TermiNexus committed 2026-10-03 08:06:39 +08:00
1 parent 0ebe2e0752
commit 94d2bf5047
3 files changed
+134 -75

No files matched your search

+108 -36
View File
@@ -31,50 +31,122 @@ import lib.Stub.StubMerger as StubMerger
# ============================================================
# ============================================================
# IsDeclOnlyModule - 判断模块是否为纯声明文件(读 {temp_dir}/{sha1}.text.ll 扫描是否含 "define " 行)
# WriteModuleFuncMeta - 落盘 {sha1}.meta 的函数定义清单(结构化 sidecar)
#
# 返回 1 = 纯声明(无函数体,如全 pass 的模块,无需 .obj);0 = 实现文件(含 define 函数体);-1 = text.ll 不存在/无法判断。
# 与 Phase B+ 编译缺失 includes 时的内联判断逻辑一致,供 Phase C 链接时区分「声明文件无需 .obj」与「实现文件缺失」。
# 每行 "FUNC <mangled> DEF|DECL":DEF = 本模块定义了该符号(有函数体,等同 .text.ll 的 define 行),
# DECL = 仅声明(等同 .stub.ll 的 declare)。数据源为翻译期模型(Module.FuncHead 链表 +
# Function.IsDeclared),与 dump_ir 的 stub/text 判据同源(STUB=IsDeclared==1、TEXT==0),
# 取代「从 IR 文本反推 declare-vs-define」。
#
# 写不出(路径/打开失败)即 fail-fast:缺 meta 会使 Phase B+/C 的「声明文件判定」失效。
#
# Args: mod 已翻译完成的 LLVM 模块;temp_dir 基础目录;td_len temp_dir 长度;sha1 模块 SHA1
# Returns: 0=成功(失败经 VLogger.error 终止进程)
# ============================================================
def IsDeclOnlyModule(temp_dir: str, td_len: sizet, sha1: str) -> int:
"""判断模块是否为纯声明文件(text.ll 无 define 行)"""
def WriteModuleFuncMeta(mod: llvmlite.LLVMModule*, temp_dir: str,
td_len: sizet, sha1: str) -> int:
"""把本模块的函数定义清单写入 {sha1}.meta"""
if mod is None or temp_dir is None or sha1 is None:
VLogger.error("meta 写出:参数为空", "Meta")
return 1
mpath: str = StubMergerCollect._sliced_path(temp_dir, td_len, sha1, "meta")
if mpath is None:
VLogger.error("meta 写出:路径构造失败", "Meta")
return 1
mf: fileio.File = fileio.File(mpath, fileio.MODE.W)
if mf.closed:
VLogger.error(f"meta 写出:无法打开 {mpath}", "Meta")
return 1
cur: llvmlite.Function* = mod.FuncHead
steps: sizet = 0
while cur is not None:
steps += 1
if steps > 100000:
VLogger.error("meta 写出:函数链表成环/超限", "Meta")
break
nm: str = llvmlite.function_get_name(cur)
if nm is not None:
nlen: sizet = string.strlen(nm)
line: bytes = stdlib.malloc(nlen + 16)
if line is None:
VLogger.error("meta 写出:行缓冲分配失败", "Meta")
break
mark: str = "DECL"
if llvmlite.function_is_declared(cur) == 0:
mark = "DEF"
viperlib.snprintf(line, nlen + 16, "FUNC %s %s\n", nm, mark)
mf.write(line, string.strlen(line))
stdlib.free(line)
cur = llvmlite.function_get_next(cur)
mf.close()
stdlib.free(mpath)
return 0
# ============================================================
# _MetaHasDef - 读 {sha1}.meta,判断模块是否含函数定义("FUNC ... DEF" 行)
#
# Returns: 1=含 DEF(实现文件);0=可读但无 DEF(纯声明);-1=meta 不存在/读失败。
# ============================================================
def _MetaHasDef(temp_dir: str, td_len: sizet, sha1: str) -> int:
"""读 {sha1}.meta:含 "FUNC ... DEF" 行返回 1,无则 0,文件不可读 -1"""
if temp_dir is None or sha1 is None:
return -1
tpath: str = StubMergerCollect._sliced_path(temp_dir, td_len, sha1, "text.ll")
if tpath is None:
mpath: str = StubMergerCollect._sliced_path(temp_dir, td_len, sha1, "meta")
if mpath is None:
return -1
tf_d: fileio.File = fileio.File(tpath, fileio.MODE.R)
stdlib.free(tpath)
if tf_d.closed:
mf: fileio.File = fileio.File(mpath, fileio.MODE.R)
stdlib.free(mpath)
if mf.closed:
return -1
tbuf_d: bytes = stdlib.malloc(StubMerger.STUB_READ_BUF_SIZE)
tbr_d: int64 = 0
if tbuf_d is not None:
tbr_d = tf_d.read_all(tbuf_d, StubMerger.STUB_READ_BUF_SIZE)
tf_d.close()
if tbuf_d is None:
mbuf: bytes = stdlib.malloc(StubMerger.STUB_READ_BUF_SIZE)
mbr: int64 = 0
if mbuf is not None:
mbr = mf.read_all(mbuf, StubMerger.STUB_READ_BUF_SIZE)
mf.close()
if mbuf is None:
return -1
if tbr_d <= 0:
# 空 text.ll:无函数体,纯声明
stdlib.free(tbuf_d)
return 1
if tbr_d < StubMerger.STUB_READ_BUF_SIZE:
tbuf_d[tbr_d] = '\0'
# 逐行扫描:找 "define " 行即为实现文件
tpos_d: sizet = 0
while tpos_d < tbr_d:
tls_d: sizet = tpos_d
while tpos_d < tbr_d:
if tbuf_d[tpos_d] == '\n':
if mbr <= 0:
# 空 meta:无 DEF,纯声明
stdlib.free(mbuf)
return 0
if mbr < StubMerger.STUB_READ_BUF_SIZE:
mbuf[mbr] = '\0'
# 逐行扫描:行尾 " DEF" 即为实现文件
mpos: sizet = 0
while mpos < mbr:
mls: sizet = mpos
while mpos < mbr:
if mbuf[mpos] == '\n':
break
tpos_d += 1
tll_d: sizet = tpos_d - tls_d
if tpos_d < tbr_d:
tpos_d += 1
if tll_d >= 7 and string.strncmp(tbuf_d + tls_d, "define ", 7) == 0:
stdlib.free(tbuf_d)
return 0
stdlib.free(tbuf_d)
mpos += 1
mll: sizet = mpos - mls
if mpos < mbr:
mpos += 1
if mll > 0 and mbuf[mls + mll - 1] == '\r':
mll -= 1
if mll >= 10 and string.strncmp(mbuf + mls, "FUNC ", 5) == 0:
if mbuf[mls + mll - 4] == ' ' and string.strncmp(mbuf + mls + mll - 3, "DEF", 3) == 0:
stdlib.free(mbuf)
return 1
stdlib.free(mbuf)
return 0
# ============================================================
# IsDeclOnlyModule - 判断模块是否为纯声明文件(读 {sha1}.meta 的结构化定义清单)
#
# 返回 1 = 纯声明(无 FUNC ... DEF,如全 pass 的模块,无需 .obj);0 = 实现文件(含 FUNC ... DEF);
# -1 = meta 不存在/无法判断。供 Phase B+/C 区分「声明文件无需 .obj」与「实现文件缺失」,
# 取代原扫描 text.ll 的 "define " 行。
# ============================================================
def IsDeclOnlyModule(temp_dir: str, td_len: sizet, sha1: str) -> int:
"""判断模块是否为纯声明文件(meta 无 FUNC ... DEF 行)"""
h: int = _MetaHasDef(temp_dir, td_len, sha1)
if h < 0:
return -1
if h == 1:
return 0
return 1
# ============================================================
# _IsFuncDeclaredOrDefined - 检查 out_buf 中是否已有函数的 declare/define