From 7b006c96a043258a23fd399f87f43ae6032b2bbb Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Sat, 3 Oct 2026 07:43:03 +0800 Subject: [PATCH] =?UTF-8?q?feat(mlirlite):=20=E8=A1=A5=E9=BD=90=20Debug=20?= =?UTF-8?q?Info=20=E5=90=8C=E5=BD=A2=20API=EF=BC=8C=E5=AF=BC=E5=87=BA?= =?UTF-8?q?=E5=90=8D=E9=9B=86=E4=B8=8E=20llvmlite=20=E4=B8=80=E8=87=B4(215?= =?UTF-8?q?=3D215)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - __module.vp: 新增 DINode/DINamedMeta 类、LLVMModule 追加 6 个 DI 字段(96->144B)、module_add_di_node/module_add_named_metadata 及实例方法、DI_NODE_SIZE/DI_NAMED_SIZE - __function.vp: Function 追加 DbgRef(80->88B) + function_set_dbg - __builder.vp: IRBuilder 追加 DbgLoc(32->40B) + set/clear_debug_location 方法 + 顶层 builder_set/clear_debug_location - __init__.vp: 导出上述 7 个 DI 名字,恢复与 llvmlite 的逐名同形(215=215) - MLIR 打印阶段忽略 DI:LLVMModulePrint 不输出 !N 元数据、_emit 不读 DbgLoc,保持 MLIR 语法合法(DI 只记录不输出) - README: 记录 DI 为「同形保留/只记录不输出」,名字数更新为 215 --- mlirlite/README.md | 11 +++- mlirlite/__builder.vp | 41 ++++++++++-- mlirlite/__function.vp | 17 ++++- mlirlite/__init__.vp | 6 +- mlirlite/__module.vp | 146 +++++++++++++++++++++++++++++++++++++++-- 5 files changed, 208 insertions(+), 13 deletions(-) diff --git a/mlirlite/README.md b/mlirlite/README.md index 250a7a2..31a5078 100644 --- a/mlirlite/README.md +++ b/mlirlite/README.md @@ -25,7 +25,7 @@ | 文件 | 内容 | 与 llvmlite 的关系 | |------|------|--------------------| -| `__init__.vp` | 公共导出 + 便捷工厂(`create_function`/`const_int*`/`create_global_*` 等)+ `LLVMTypeCore`/`LLVMModuleCore` | **导入清单逐名一致(208 个名字),代码逐行一致**,仅注释不同 | +| `__init__.vp` | 公共导出 + 便捷工厂(`create_function`/`const_int*`/`create_global_*` 等)+ `LLVMTypeCore`/`LLVMModuleCore` | **导入清单逐名一致(215 个名字,含 Debug Info 全套),代码逐行一致**,仅注释不同 | | `__types.vp` | `LLVMType`(REnum) / `ParamNode` / 类型工厂 / `TypePrint` / `DeepCopyType` | 模型与工厂**逐名同形**;`TypePrint` 改为 MLIR 语义(具名结构体内联为 `!llvm.struct<"name", (…)>`),`PrintStructDefinition` 变为空操作,新增打印期命名结构体登记表(§2.10) | | `__values.vp` | `Value` / `ConstInt`/`ConstNull`/`ConstZero`/`ConstFloat`/`SSAValue` / `ValuePrint` | 模型与工厂同形;仅 `ValuePrint` 改为 MLIR 语义 | | `__function.vp` | `Line`/`BasicBlock`/`Param`/`Function` + 工厂 + `RenumberSSA` + 窥孔 + `FunctionPrint` | 模型、`RenumberSSA`、本地窥孔**逐行一致**;`FunctionPrint` 重写为 MLIR 渲染 | @@ -528,6 +528,14 @@ packed"的组合,无需(也无处)为其单独报错。登记表每槽 16 类型定义行。`module_add_named_type` 保留模型语义(去重 / opaque 就地替换)并作为 打印期登记表的来源(`_MlirPublishNamedTypes`,见 §2.10),`PrintStructDefinition` 输出空串(保留 API 同形)。 +- **Debug Info**(`module_add_di_node` / `module_add_named_metadata` / + `function_set_dbg` / `builder_set_(clear_)debug_location`、`DINode` / + `DINamedMeta`、`LLVMModule.DIMeta*`/`DINamed*`、`Function.DbgRef`、 + `IRBuilder.DbgLoc`):为保持与 llvmlite **逐名同形**(并让 TransPyV 的 + `DebugInfoGen` 在 `llvmlite.`→`mlirlite.` 改名后可编译),本库**完整保留这些名字 + 与模型字段/布局**(`LLVMModule` 144B、`Function` 88B、`IRBuilder` 40B, + 与 llvmlite 同布局);但 MLIR 语法没有 `!N = …` 元数据与 `, !dbg !N` 后缀, + 故**全部只记录、不输出**(`LLVMModulePrint` 不打印 DI 节点,`_emit` 不读 `DbgLoc`)。 --- @@ -549,6 +557,7 @@ packed"的组合,无需(也无处)为其单独报错。登记表每槽 16 | 12 | `G_PeepEnable` | 语义不变:窥孔作用在**中间文本**(`ret zeroinitializer→0/null`、入口槽 store→load 转发、no-op bitcast 消除),与 MLIR 渲染正交(T3 与 MLIR 的 no-op 折叠叠加,结果一致) | | 13 | `module_set_named_type_packed` | 语义不变(记录 `NamedTypeNode.IsPacked`);MLIR 侧**已参与渲染**:具名结构体在使用处内联为 `!llvm.struct<"name", packed (…)>`(见 §2.10) | | 14 | 中间指令文本(`Line.Buf`) | **内容与 llvmlite 不同**:builders 内嵌类型经 `_type_str` → `TypePrint` 已是 MLIR 形态(`load i32, !llvm.ptr %p` 而非 `load i32, i32* %p`)。文本层使用者(窥孔、verify)按名称/结构匹配,语义不受影响 | +| 15 | Debug Info 全套(`module_add_di_node` / `module_add_named_metadata` / `function_set_dbg` / `builder_set_(clear_)debug_location`、`DINode`/`DINamedMeta`、`DIMeta*`/`DINamed*`/`DbgRef`/`DbgLoc`) | **逐名同形、布局同形**(LLVMModule 144B / Function 88B / IRBuilder 40B),但 MLIR 无 `!N = …` 元数据与 `, !dbg !N` 后缀 ⇒ **只记录、不输出**(见 §3.3) | --- diff --git a/mlirlite/__builder.vp b/mlirlite/__builder.vp index 98624c2..968f992 100644 --- a/mlirlite/__builder.vp +++ b/mlirlite/__builder.vp @@ -25,7 +25,7 @@ from .__function import Function, BasicBlock, block_append_text, block_set_termi # r = builder.build_load(i32_ty, a) # builder.build_ret(r) # -# 注意: 加 @t.NoVTable 以与硬编码 BUILDER_SIZE=32 保持一致 +# 注意: 加 @t.NoVTable 以与硬编码 BUILDER_SIZE=40 保持一致 # (方法以实例方法实现,无虚表;文件末尾的同名顶层函数为一行委托)。 # ============================================================ novirtual class IRBuilder: @@ -33,6 +33,7 @@ novirtual class IRBuilder: Func: rawptr[Function] # 所属函数 CurBlock: rawptr[BasicBlock] # 当前插入点 Counter: int # SSA 名计数器 + DbgLoc: str # current DILocation ref(同形保留;MLIR 打印阶段忽略,不发 !dbg 后缀) # ============================================================ # 内部辅助 @@ -75,11 +76,29 @@ novirtual class IRBuilder: def _emit(self, text: str): - """将指令文本追加到当前块""" + """将指令文本追加到当前块 + + 与 llvmlite 的差异:MLIR 语法没有 `, !dbg !N` 后缀,故本实现**故意不**读取 + DbgLoc(set_debug_location 只记录模型,不改变输出)。其余调用方逻辑一致。 + """ if self is None or self.CurBlock is None: return block_append_text(self.Pool, self.CurBlock, text) + def set_debug_location(self, ref: str): + """Set the current DILocation ref(同形保留;MLIR 侧仅记录,不影响输出) + + ref=None clears it. + """ + if self is None: return + self.DbgLoc = ref + + def clear_debug_location(self): + """Clear the current DILocation ref(同形保留;MLIR 侧仅记录)""" + if self is None: return + self.DbgLoc = None + + def _mark_terminated(self): """标记当前块已终止""" if self is None or self.CurBlock is None: return @@ -1164,8 +1183,8 @@ novirtual class IRBuilder: # ============================================================ # 工厂函数 # ============================================================ -# IRBuilder 硬编码大小: Pool(8) + Func(8) + CurBlock(8) + Counter(4) = 32 字节 -BUILDER_SIZE: t.CDefine = 32 +# IRBuilder 硬编码大小: Pool(8) + Func(8) + CurBlock(8) + Counter(4) + DbgLoc(8) = 40 字节(与 llvmlite 同布局) +BUILDER_SIZE: t.CDefine = 40 def new_builder(pool: memhub.MemBuddy*, func: rawptr[Function]) -> rawptr[IRBuilder]: """创建 IRBuilder,关联到函数 func""" @@ -1176,6 +1195,7 @@ def new_builder(pool: memhub.MemBuddy*, func: rawptr[Function]) -> rawptr[IRBuil ptr.Func = func ptr.CurBlock = None ptr.Counter = 0 + ptr.DbgLoc = None return ptr @@ -1228,6 +1248,19 @@ def builder_cur_block_is_terminated(builder: rawptr[IRBuilder]) -> int: return builder.builder_cur_block_is_terminated() +# ============================================================ +# 调试位置(同形保留;MLIR 打印阶段忽略) +# ============================================================ +def builder_set_debug_location(builder: rawptr[IRBuilder], ref: str): + """Set the current DILocation ref(同形保留;MLIR 侧仅记录,不影响输出)""" + builder.set_debug_location(ref) + + +def builder_clear_debug_location(builder: rawptr[IRBuilder]): + """Clear the current DILocation ref(同形保留;MLIR 侧仅记录)""" + builder.clear_debug_location() + + # ============================================================ # 内存指令 # ============================================================ diff --git a/mlirlite/__function.vp b/mlirlite/__function.vp index fbdc471..a2eccc0 100644 --- a/mlirlite/__function.vp +++ b/mlirlite/__function.vp @@ -87,7 +87,8 @@ novirtual class Function(GSListNode[Function]): Attrs: str # 函数属性文本(None=无属性) AttrGroup: str # 字符串属性组内容(如 '"section"=".text.startup"',None=无) AttrGroupId: int # 属性组编号(>0 时函数行输出 #N,模块尾输出 attributes #N) - NameLen: sizet # 函数名长度(创建时一次算好,恒等于 strlen(Name);追加在末尾,既有字段偏移不变) + NameLen: sizet # 函数名长度(创建时一次算好,恒等于 strlen(Name);追加在末尾,既有字段偏移不变) + DbgRef: str # DISubprogram ref(同形保留;MLIR 打印阶段忽略,如 "!3") # ============================================================ @@ -148,8 +149,8 @@ def new_param(pool: memhub.MemBuddy*, ty: rawptr[LLVMType], return ptr -# Function 硬编码大小: Next(8) + Name(8) + RetTy(8) + Params(8) + Blocks(8) + IsDeclared(4) + IsVarArg(4) + Attrs(8) + AttrGroup(8) + AttrGroupId(8) + NameLen(8) = 80 字节 -FUNC_SIZE: t.CDefine = 80 +# Function 硬编码大小: Next(8) + Name(8) + RetTy(8) + Params(8) + Blocks(8) + IsDeclared(4) + IsVarArg(4) + Attrs(8) + AttrGroup(8) + AttrGroupId(8) + NameLen(8) + DbgRef(8) = 88 字节(与 llvmlite 同布局) +FUNC_SIZE: t.CDefine = 88 def new_function(pool: memhub.MemBuddy*, name: str, ret_ty: rawptr[LLVMType]) -> rawptr[Function]: @@ -343,6 +344,16 @@ def param_set_attrs(param: rawptr[Param], attrs: str): param.Attrs = attrs +def function_set_dbg(func: rawptr[Function], ref: str): + """Set the function-level debug ref (DISubprogram node ref, e.g. "!3"). + + 同形保留:MLIR 打印阶段忽略该引用(FunctionPrint 不输出 !dbg), + 故本调用只记录模型、不改变输出。ref=None 清除。 + """ + if func is None: return + func.DbgRef = ref + + # ============================================================ # _ll_name_needs_quote - 检查符号名在 MLIR 中是否需要 @"…" 引号形式 # diff --git a/mlirlite/__init__.vp b/mlirlite/__init__.vp index 8a88bbe..6b8be65 100644 --- a/mlirlite/__init__.vp +++ b/mlirlite/__init__.vp @@ -38,16 +38,19 @@ from .__function import ( block_append_line, block_append_text, function_set_attrs, param_set_attrs, function_set_attr_group, + function_set_dbg, function_get_name, function_get_name_len, function_get_ret_ty, function_get_params, function_get_param_head, function_get_next, function_is_declared, param_get_name, param_get_ty, param_get_next, FunctionPrint, G_PeepEnable, ) from .__module import ( - LLVMModule, GlobalVariable, NamedTypeNode, new_module, new_global_variable, + LLVMModule, GlobalVariable, NamedTypeNode, DINode, DINamedMeta, + new_module, new_global_variable, module_add_function, module_add_global, module_add_named_type, module_set_named_type_packed, module_set_target, module_set_datalayout, + module_add_di_node, module_add_named_metadata, global_set_constant, global_set_linkage, global_set_unnamed_addr, global_set_section, LLVMModulePrint, OUTPUT_FULL, OUTPUT_STUB, OUTPUT_TEXT, module_ensure_opaque_for_type, @@ -55,6 +58,7 @@ from .__module import ( from .__builder import ( IRBuilder, new_builder, position_at_end, builder_cur_block_is_terminated, + builder_set_debug_location, builder_clear_debug_location, build_alloca, build_alloca_aligned, build_alloca_at_entry, build_load, build_store, build_add, build_sub, build_mul, build_sdiv, build_udiv, build_srem, build_urem, build_and, build_or, build_xor, build_shl, build_lshr, build_ashr, diff --git a/mlirlite/__module.vp b/mlirlite/__module.vp index 0cde7b8..7f5dc6a 100644 --- a/mlirlite/__module.vp +++ b/mlirlite/__module.vp @@ -48,6 +48,27 @@ class NamedTypeNode(GSListNode[NamedTypeNode]): IsPacked: int # 1=packed 结构体(MLIR: !llvm.struct<"name", packed (…)>,无字段填充) +# ============================================================ +# DINode: DI metadata node(同形保留;MLIR 打印阶段忽略) +# +# 与 includes/llvmlite 逐名同形:Debug Info 在 MLIR 后端无对应概念,故本库 +# 仅记录模型(供 TransPyV 的 DebugInfoGen 在 llvmlite.→mlirlite. 改名后仍可 +# 编译),LLVMModulePrint **不输出**这些节点(输出会破坏 MLIR 语法)。 +# ============================================================ +@t.NoVTable +class DINode(GSListNode[DINode]): + Text: str # node body, e.g. "!DIFile(filename: \"a.vp\", directory: \"/x\")" + + +# ============================================================ +# DINamedMeta: named metadata(同形保留;MLIR 打印阶段忽略) +# ============================================================ +@t.NoVTable +class DINamedMeta(GSListNode[DINamedMeta]): + Name: str # e.g. "llvm.dbg.cu" / "llvm.module.flags" + Refs: str # reference list text, e.g. "!1" + + # ============================================================ # LLVMModule: LLVM IR 模块容器 # @@ -70,7 +91,13 @@ class LLVMModule: NamedTypeHead: rawptr[NamedTypeNode] # 命名结构体类型链表头 NamedTypeTail: rawptr[NamedTypeNode] # 命名结构体类型链表尾 NamedTypeCount: sizet # 命名结构体类型计数 - # 总计: 12 字段 * 8 = 96 字节(无 vtable) + DIMetaHead: rawptr[DINode] # DI metadata node list head(同形保留;MLIR 不打印) + DIMetaTail: rawptr[DINode] # DI metadata node list tail + DIMetaCount: sizet # DI node count (= next !N id) + DINamedHead: rawptr[DINamedMeta] # named metadata list head + DINamedTail: rawptr[DINamedMeta] # named metadata list tail + DINamedCount: sizet # named metadata count + # 总计: 18 字段 * 8 = 144 字节(无 vtable;与 includes/llvmlite 同布局) # ============================================================ # 实例方法(对象化重构:原 module_* 顶层函数改写为方法, @@ -111,6 +138,89 @@ class LLVMModule: if self is None: return self.DataLayout = layout + # ---- DI debug metadata(同形保留;MLIR 打印阶段忽略,仅记录模型)---- + def add_di_node(self, pool: memhub.MemBuddy*, text: str) -> int: + """Append a DI metadata node; return its !N id (0-based, unique), -1 on failure. + + text is the node body incl. !M references built from earlier ids. + MLIR 后端无 DI 概念:节点仅登记在模型里(LLVMModulePrint 不输出), + 从而 TransPyV 的 DebugInfoGen 在改名后仍可编译、且不影响 MLIR 输出。 + """ + if self is None or pool is None or text is None: + return -1 + node: rawptr[DINode] = pool.alloc(DI_NODE_SIZE) + if node is None: + return -1 + string.memset(node, 0, DI_NODE_SIZE) + # copy body (caller buffer may be reused) + tlen: sizet = string.strlen(text) + tcopy: str = pool.alloc(tlen + 1) + if tcopy is None: + return -1 + string.strcpy(tcopy, text) + node.Text = tcopy + if self.DIMetaHead is None: + self.DIMetaHead = node + else: + self.DIMetaTail.Next = node + self.DIMetaTail = node + node_id: int = int(self.DIMetaCount) + self.DIMetaCount += 1 + return node_id + + def add_named_metadata(self, pool: memhub.MemBuddy*, name: str, refs: str): + """Register named metadata "! = !{ }"; merge into an existing + entry with the same name (refs is the brace body, e.g. "!3"). + + MLIR 侧仅记录模型,不产生输出(LLVMModulePrint 不输出 DI)。 + """ + if self is None or pool is None or name is None: + return + cur: rawptr[DINamedMeta] = self.DINamedHead + cur_steps: sizet = 0 + while cur is not None: + cur_steps += 1 + if cur_steps > IR_DUMP_CHAIN_LIMIT: + stdio.printf("[IR-DUMP] 链表成环: module di named(DINamedCount=%zu,dump 终止)\n", + self.DINamedCount) + stdlib.exit(1) + if cur.Name is not None and string.strcmp(cur.Name, name) == 0: + if refs is not None: + old_len: sizet = 0 + if cur.Refs is not None: + old_len = string.strlen(cur.Refs) + merged: str = pool.alloc(old_len + string.strlen(refs) + 3) + if merged is not None: + merged[0] = '\0' + if cur.Refs is not None: + string.strcat(merged, cur.Refs) + string.strcat(merged, ", ") + string.strcat(merged, refs) + cur.Refs = merged + return + cur = cur.Next + entry: rawptr[DINamedMeta] = pool.alloc(DI_NAMED_SIZE) + if entry is None: + return + string.memset(entry, 0, DI_NAMED_SIZE) + ncopy: str = pool.alloc(string.strlen(name) + 1) + if ncopy is None: + return + string.strcpy(ncopy, name) + entry.Name = ncopy + if refs is not None: + rcopy: str = pool.alloc(string.strlen(refs) + 1) + if rcopy is None: + return + string.strcpy(rcopy, refs) + entry.Refs = rcopy + if self.DINamedHead is None: + self.DINamedHead = entry + else: + self.DINamedTail.Next = entry + self.DINamedTail = entry + self.DINamedCount += 1 + # ---- 命名结构体类型管理 ---- def add_named_type(self, pool: memhub.MemBuddy*, ty: rawptr[LLVMType]): """登记命名结构体类型到模块(MLIR 侧仅保留模型,不产生输出) @@ -349,10 +459,11 @@ def _MlirPublishNamedTypes(mod: rawptr[LLVMModule], pool: memhub.MemBuddy*): # ============================================================ def new_module(pool: memhub.MemBuddy*, name: str) -> rawptr[LLVMModule]: """创建一个模块""" - # 硬编码 96 字节:12 字段 * 8 字节(无 vtable,@t.NoVTable) - ptr: rawptr[LLVMModule] = pool.alloc(96) + # 硬编码 144 字节:18 字段 * 8 字节(无 vtable,@t.NoVTable) + # 含 DI 字段(DIMetaHead/Tail/Count、DINamedHead/Tail/Count),与 llvmlite 同布局。 + ptr: rawptr[LLVMModule] = pool.alloc(144) if ptr is None: return None - string.memset(ptr, 0, 96) + string.memset(ptr, 0, 144) ptr.Name = name ptr.FuncHead = None ptr.FuncTail = None @@ -365,6 +476,12 @@ def new_module(pool: memhub.MemBuddy*, name: str) -> rawptr[LLVMModule]: ptr.NamedTypeHead = None ptr.NamedTypeTail = None ptr.NamedTypeCount = 0 + ptr.DIMetaHead = None + ptr.DIMetaTail = None + ptr.DIMetaCount = 0 + ptr.DINamedHead = None + ptr.DINamedTail = None + ptr.DINamedCount = 0 return ptr @@ -374,6 +491,12 @@ GV_SIZE: t.CDefine = 72 # NamedTypeNode 硬编码大小: Next(8) + Ty(8) + IsPacked(8) = 24 字节 NAMED_TYPE_NODE_SIZE: t.CDefine = 24 +# DINode 硬编码大小: Next(8) + Text(8) = 16 字节(同 llvmlite) +DI_NODE_SIZE: t.CDefine = 16 + +# DINamedMeta 硬编码大小: Next(8) + Name(8) + Refs(8) = 24 字节(同 llvmlite) +DI_NAMED_SIZE: t.CDefine = 24 + def new_global_variable(pool: memhub.MemBuddy*, name: str, ty: rawptr[LLVMType]) -> rawptr[GlobalVariable]: """创建一个全局变量""" @@ -417,6 +540,21 @@ def module_set_datalayout(mod: rawptr[LLVMModule], layout: str): mod.set_datalayout(layout) +# ============================================================ +# DI debug metadata(同形保留;MLIR 打印阶段忽略,仅记录模型) +# ============================================================ +def module_add_di_node(mod: rawptr[LLVMModule], pool: memhub.MemBuddy*, + text: str) -> int: + """Append a DI metadata node; return its !N id (-1 on failure)""" + return mod.add_di_node(pool, text) + + +def module_add_named_metadata(mod: rawptr[LLVMModule], pool: memhub.MemBuddy*, + name: str, refs: str): + """Register named metadata "! = !{ }" """ + mod.add_named_metadata(pool, name, refs) + + # ============================================================ # 命名结构体类型管理 # ============================================================