feat(tpc): 函数级 DWARF 调试元数据 + 合并 IR 元数据规整
DWARF: 新增 LLVMCG/DebugInfo.py(DebugInfoEmitter)——每模块一个 DIFile/DICompileUnit、每个 define 一个 DISubprogram 并在函数入口首条指令挂 DILocation,模块落盘前补 !llvm.dbg.cu 与 !llvm.module.flags(Debug Info Version 3)。开关:新增 --dwarf(默认关闭),dwarf_enabled = args.dwarf or args.asan,沿 Phase2Translator → _translate_file → Translator.DwarfEnabled → LlvmCodeGenerator.dwarf_enabled 下传。define 之外的 declare 不挂。include 库刻意不给 DI(其 .obj 进跨项目共享的 includes.binary 缓存,注入会污染缓存)
关键约束(踩过的坑,已在探针中实测):DICompileUnit 与 DISubprogram 必须 is_distinct=True;emissionKind 用 FullDebug 而非 Full;spFlags 用 DISPFlagDefinition;DISubprogram 必带 type=DISubroutineType,缺了 llc 会崩 0xC0000005;模块级必须有 !llvm.dbg.cu + Debug Info Version 3
IRMetadataFix: 新增 SanitizeIRMetadata,在 _llc_compile 入口统一规整 IR——BuildCombinedIR 是多模块 IR 文本直接拼接,--dwarf 后每个片段自带 !0..!N 与两份命名元数据,22383 行样本里 !0/!1 各重复 67 次导致 opt/llc 报 Metadata id is already used。实现:按块重编号 !N 并改写 !dbg/命名元数据引用、!llvm.dbg.cu 全量聚合、其它命名元数据全同去重;无元数据文件逐字节 no-op、幂等(1.7MB/0.30s)
顺带修 _AddWeakComdat:函数头正则跨行吞换行,--dwarf 把 !dbg 放到 define 行尾后 comdat 被插到 ! 附着之后,llc 报 expected { in function body(现场 52 个 define 中 36 个中招);改为插在附着之前,无 !dbg 时产物逐字节不变
已自证:llc/opt RC=0、行表含 .vp 文件名与行号、opt -passes=forceattrs,asan 与 llvm-link/always-inline 均不丢 !dbg。已知待办:llc 现报 inlinable function call ... must have a !dbg location ⇒ 需补语句/调用点级 !dbg(否则警告 ignoring invalid debug info 会丢弃整份 DI)
This commit is contained in:
1 parent
033c0a7771
commit
43e7cdd2cc
9 files changed
+480
-27
No files matched your search
@@ -1782,22 +1782,22 @@ class FunctionHandle(BaseHandle):
|
||||
# 导致方法调用查找 ndarray.sum 而非 ndarray[double].sum。
|
||||
if param_name in Gen.var_struct_class:
|
||||
_existing_ps: str = Gen.var_struct_class[param_name]
|
||||
# 指针占位名(rowptr / {sha1}.rowptr / rowptr[...])是模块限定
|
||||
# 指针占位名(rawptr / {sha1}.rawptr / rawptr[...])是模块限定
|
||||
# struct 联合(llvmlite.Function | t.CPtr)被 resolver 退化
|
||||
# 的产物,必须允许 FindStructNameInAnnotation 短名修正
|
||||
# (否则 func.IsVarArg → "属性在类 'rowptr' 中找不到")。
|
||||
if not (_existing_ps == 'rowptr' or '.rowptr' in _existing_ps
|
||||
or _existing_ps.startswith('rowptr[')):
|
||||
# (否则 func.IsVarArg → "属性在类 'rawptr' 中找不到")。
|
||||
if not (_existing_ps == 'rawptr' or '.rawptr' in _existing_ps
|
||||
or _existing_ps.startswith('rawptr[')):
|
||||
continue
|
||||
found_struct: str | None = FindStructNameInAnnotation(arg.annotation, Gen.structs)
|
||||
if found_struct:
|
||||
Gen.var_struct_class[param_name] = found_struct
|
||||
# 普通类注解形参(非 BinOp 联合):rowptr[X] / t.CPtr[X] / X / t.X
|
||||
# 普通类注解形参(非 BinOp 联合):rawptr[X] / t.CPtr[X] / X / t.X
|
||||
# 一律按"声明类"登记 var_struct_class。避免按 param.type.pointee 匹配
|
||||
# 到泛型父特化(如 class Function(GSListNode[Function]) 的形参 func 被
|
||||
# 登记成 GSListNode[Function],其 struct 仅含 Next → func.Blocks 访问
|
||||
# fast-fail "属性 'Blocks' 在类 'GSListNode[Function]' 中找不到")。
|
||||
# 泛型占位(rowptr[T])的 T 不在 Gen.structs,自动跳过、保留 pointee 匹配。
|
||||
# 泛型占位(rawptr[T])的 T 不在 Gen.structs,自动跳过、保留 pointee 匹配。
|
||||
for i, arg in enumerate(Node.args.args):
|
||||
if arg.annotation is None:
|
||||
continue
|
||||
@@ -1815,7 +1815,7 @@ class FunctionHandle(BaseHandle):
|
||||
elif isinstance(ann, ast.Subscript):
|
||||
subv = ann.value
|
||||
subname = getattr(subv, 'id', None) or getattr(subv, 'attr', '')
|
||||
if subname in ('rowptr', 'CPtr', 'Ptr'):
|
||||
if subname in ('rawptr', 'CPtr', 'Ptr'):
|
||||
slc = ann.slice
|
||||
if isinstance(slc, ast.Name):
|
||||
target = slc.id
|
||||
@@ -1943,6 +1943,22 @@ class FunctionHandle(BaseHandle):
|
||||
except Exception:
|
||||
pass
|
||||
raise
|
||||
# 函数级 DWARF 调试元数据(--dwarf / --asan 自动开启):为每个 define 建
|
||||
# DISubprogram 挂 func.metadata["dbg"],并在入口块第一条指令挂 DILocation
|
||||
# (line/column = 该 def 语句的位置),使 DWARF 行表至少有一条覆盖函数地址
|
||||
# 区间的行。declare/extern 在此之前已 return,不会被挂 !dbg;未启用时
|
||||
# _GetDebugInfo() 返回 None,不产生任何 IR 差异(零影响)。
|
||||
_DbgInfo = Gen._GetDebugInfo()
|
||||
if _DbgInfo is not None:
|
||||
try:
|
||||
_DbgLoc = _DbgInfo.AttachFunction(
|
||||
func, getattr(Node, 'lineno', 0) or 0, getattr(Node, 'col_offset', 0) + 1)
|
||||
if EntryBlock.instructions:
|
||||
EntryBlock.instructions[0].metadata['dbg'] = _DbgLoc
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
raise
|
||||
_vlog().warning(f"发射调试元数据失败: {_e}", "Exception")
|
||||
if not Gen.builder.block.is_terminated:
|
||||
if 'naked' in fn_attrs:
|
||||
Gen.builder.unreachable()
|
||||
|
||||
Reference in new issue
Block a user