同 includes 的同类修正:把一级指针 i8* 隐式塞进二级注解(i8** / str*)。 TransPyV 侧 coerce(ExprGenBase._ptr_cast_reason)没有 TPC 那样的「值侧是显式 指针 cast ⇒ 按 bitcast 重解释」豁免,故一旦用新构建的 TransPyV 编到这些文件 必然 fail-fast(回归测试首爆点在 includes/llvmlite 侧,本仓同形态站点随后必然 同样触发)。 涉及的两种形态: · `slot: str | t.CPtr = (t.CPtr)(addr)` —— cast 目标是一级 t.CPtr · `nm_slot: str* = (t.CPtr)(addr)` —— 注解 str* 即 i8** 统一改为 cast 到声明类型:`(str | t.CPtr)(addr)` / `str*(addr)`(后者与 includes/sys.vp `argv_arr: str* = str*(...)` 同一写法)。 本仓 47 处 / 6 文件: App/lib/core/Gen/VarGenMixin.vp 3 App/lib/core/Gen/TranslatorGenMixin.vp 8 App/lib/core/Gen/Func/FuncGenMixin.vp 13 App/lib/core/Gen/AsyncGenMixin.vp 15 App/lib/core/Gen/DebugInfoGen.vp 6 App/lib/Stub/StubGen/Converter.vp 2 Converter.vp:107 的 `_g_pyi_cdef_names: str | t.CPtr = None` 保持原样 (None 即空指针,任何指针类型均可,不属本类问题)。 只提交本 6 个文件;本仓其余未提交改动(CallGenBase/CallGenDispatch/CallGenFd/ CallGenProp/Generator/Translator/VLogger)与本迁移无关,保持不动。
472 lines
19 KiB
Plaintext
472 lines
19 KiB
Plaintext
import t, c
|
||
from stdint import *
|
||
import llvmlite
|
||
import memhub
|
||
import string
|
||
import stdlib
|
||
import viperlib
|
||
import w32.win32file as w32file
|
||
import lib.core.VLogger as VLogger
|
||
|
||
# ============================================================
|
||
# DebugInfoGen - function-level DWARF metadata emitter (llvmlite text IR)
|
||
#
|
||
# Node layout mirrors TPC lib/core/LLVMCG/DebugInfo.py node-for-node:
|
||
# !DIFile -> !{ null } -> !DISubroutineType -> distinct !DICompileUnit
|
||
# -> distinct !DISubprogram (per define) -> !DILocation (per statement)
|
||
# module tail: !llvm.dbg.cu + !llvm.module.flags (Debug Info Version 3)
|
||
#
|
||
# Enabled only while --traceback is on: the Phase layer mirrors
|
||
# BuildPipeline._traceback_mode here via SetEnabled(). While disabled every
|
||
# entry point returns before touching any llvmlite DI API, so the emitted IR
|
||
# stays byte-identical to the pre-DWARF output.
|
||
#
|
||
# Scope/statement hooks are driven from the Gen layer:
|
||
# Translator.translate -> BeginModule / Finalize
|
||
# FuncGenDef.translate_function_def / ClassGenVTable._translate_method /
|
||
# FuncGenMixin (nested + lambda) -> PushFunction / PopFunction
|
||
# StmtGenMixin.translate_stmt -> SetStatement
|
||
# ============================================================
|
||
|
||
# ---- module-scope state (reset per module by BeginModule) ----
|
||
_g_enabled: int = 0
|
||
_g_finalized: int = 0
|
||
_g_mod: llvmlite.LLVMModule* = None
|
||
_g_file_path: str = None
|
||
_g_file_id: int = -1
|
||
_g_null_id: int = -1
|
||
_g_subtype_id: int = -1
|
||
_g_cu_id: int = -1
|
||
_g_cur_sp: int = -1
|
||
_g_cur_entry_ref: str = None
|
||
_g_cur_builder: llvmlite.IRBuilder* = None
|
||
_g_depth: int = 0
|
||
|
||
# Push/Pop save stack: enclosing (sp id + 1, entry DILocation ref, builder)
|
||
# per level. +1 so 0 means "no enclosing function" (sp ids are >= 0). The saved
|
||
# builder is what makes SetStatement reject a builder that is not the one the
|
||
# current DISubprogram was pushed on (e.g. an async state machine emitted inside
|
||
# a bracketed function): such instructions must carry no !dbg, otherwise LLVM's
|
||
# verifier rejects "!dbg attachment points at wrong subprogram for function".
|
||
DBG_STACK_MAX: t.CDefine = 256
|
||
_g_stk_sp: sizet* = None
|
||
_g_stk_ref: str = None
|
||
_g_stk_bld: str = None
|
||
|
||
# DILocation cache: direct-mapped, up to 8-way linear probe, key (sp, line, col).
|
||
DBG_LOC_SLOTS: t.CDefine = 8192
|
||
DBG_LOC_PROBE: t.CDefine = 8
|
||
DBG_LOC_KEY_STRIDE: t.CDefine = 3
|
||
_g_loc_key: sizet* = None
|
||
_g_loc_ref: str = None
|
||
_g_loc_used: bytes = None
|
||
|
||
|
||
# ============================================================
|
||
# SetEnabled / IsEnabled - mirror the --traceback switch
|
||
# ============================================================
|
||
def SetEnabled(flag: bool) -> int:
|
||
"""Enable/disable DI emission (mirrors BuildPipeline._traceback_mode)."""
|
||
global _g_enabled
|
||
if flag:
|
||
_g_enabled = 1
|
||
else:
|
||
_g_enabled = 0
|
||
return 0
|
||
|
||
|
||
def IsEnabled() -> int:
|
||
return _g_enabled
|
||
|
||
|
||
# ============================================================
|
||
# _EnsureStorage - lazily allocate the long-lived stack / cache buffers
|
||
# ============================================================
|
||
def _EnsureStorage() -> int:
|
||
global _g_stk_sp, _g_stk_ref, _g_stk_bld, _g_loc_key, _g_loc_ref, _g_loc_used
|
||
if _g_stk_sp is not None:
|
||
return 0
|
||
sbuf1: bytes = stdlib.malloc(DBG_STACK_MAX * 8)
|
||
sbuf2: bytes = stdlib.malloc(DBG_STACK_MAX * 8)
|
||
sbuf3: bytes = stdlib.malloc(DBG_STACK_MAX * 8)
|
||
kbuf: bytes = stdlib.malloc(DBG_LOC_SLOTS * DBG_LOC_KEY_STRIDE * 8)
|
||
rbuf: bytes = stdlib.malloc(DBG_LOC_SLOTS * 8)
|
||
ubuf: bytes = stdlib.malloc(DBG_LOC_SLOTS)
|
||
if sbuf1 is None or sbuf2 is None or sbuf3 is None or kbuf is None or rbuf is None or ubuf is None:
|
||
VLogger.error("--traceback: DWARF 元数据缓冲分配失败,终止编译", "DWARF")
|
||
return 1
|
||
string.memset(sbuf1, 0, DBG_STACK_MAX * 8)
|
||
string.memset(sbuf2, 0, DBG_STACK_MAX * 8)
|
||
string.memset(sbuf3, 0, DBG_STACK_MAX * 8)
|
||
string.memset(kbuf, 0, DBG_LOC_SLOTS * DBG_LOC_KEY_STRIDE * 8)
|
||
string.memset(rbuf, 0, DBG_LOC_SLOTS * 8)
|
||
string.memset(ubuf, 0, DBG_LOC_SLOTS)
|
||
_g_stk_sp = (sizet*)(sbuf1)
|
||
_g_stk_ref = sbuf2
|
||
_g_stk_bld = sbuf3
|
||
_g_loc_key = (sizet*)(kbuf)
|
||
_g_loc_ref = rbuf
|
||
_g_loc_used = ubuf
|
||
return 0
|
||
|
||
|
||
def _RefOf(pool: memhub.MemBuddy*, node_id: int) -> str:
|
||
"""Allocate a persistent "!N" reference string for a DI node id."""
|
||
buf: str = pool.alloc(24)
|
||
if buf is None:
|
||
return None
|
||
viperlib.snprintf(buf, 24, "!%d", node_id)
|
||
return buf
|
||
|
||
|
||
# ============================================================
|
||
# BeginModule - start of one module translation
|
||
# ============================================================
|
||
def BeginModule(mod: llvmlite.LLVMModule*, file_path: str) -> int:
|
||
"""Reset per-module DI state. Call once at the start of each module."""
|
||
global _g_mod, _g_file_path, _g_finalized, _g_file_id, _g_null_id
|
||
global _g_subtype_id, _g_cu_id, _g_cur_sp, _g_cur_entry_ref, _g_cur_builder, _g_depth
|
||
if _g_enabled == 0:
|
||
return 0
|
||
if _EnsureStorage() != 0:
|
||
return 1
|
||
_g_mod = mod
|
||
_g_file_path = file_path
|
||
_g_finalized = 0
|
||
_g_file_id = -1
|
||
_g_null_id = -1
|
||
_g_subtype_id = -1
|
||
_g_cu_id = -1
|
||
_g_cur_sp = -1
|
||
_g_cur_entry_ref = None
|
||
_g_cur_builder = None
|
||
_g_depth = 0
|
||
if _g_loc_used is not None:
|
||
string.memset(_g_loc_used, 0, DBG_LOC_SLOTS)
|
||
return 0
|
||
|
||
|
||
# ============================================================
|
||
# _EnsureModuleNodes - DIFile / !{ null } / DISubroutineType / DICompileUnit
|
||
# (created lazily at the first define, once per module)
|
||
# ============================================================
|
||
def _EnsureModuleNodes(pool: memhub.MemBuddy*) -> int:
|
||
global _g_file_id, _g_null_id, _g_subtype_id, _g_cu_id
|
||
if _g_cu_id >= 0:
|
||
return 0
|
||
mod: llvmlite.LLVMModule* = _g_mod
|
||
if mod is None:
|
||
return 1
|
||
# DIFile: **绝对**路径(正斜杠),filename 保留整条路径。
|
||
# 为什么必须绝对:本工程给 CurrentFile 的是**项目相对**路径(如
|
||
# "./Test/LLvmLiteTest/App/main.vp"),LLVM 会把该目录写成 CU 的 DW_AT_comp_dir,
|
||
# 而主文件条目用 `dir_index: 0` 指向 comp_dir;stackmap 写入端只解析
|
||
# `llvm-dwarfdump --debug-line`(其中**没有** comp_dir)⇒ 行记录只能退化成裸文件名
|
||
# "main.vp":运行期既显示不全,也无法按路径重读源码行(实证:曾整段栈都打印
|
||
# `File "main.vp", line N` 而无源码行)。
|
||
# 绝对化后,无论 LLVM 保留整条 name(写入端 `_tb_is_abs_path` 命中 ⇒ 原样采用)
|
||
# 还是把它拆成 dir+basename(dir_index 指向同一个绝对目录 ⇒ 拼回绝对路径),
|
||
# 结果都是绝对路径 —— 故本改动不需要动写入端。
|
||
src: str = _g_file_path
|
||
if src is None:
|
||
src = ""
|
||
slen: sizet = string.strlen(src)
|
||
cap_n: sizet = slen + 4112
|
||
nbuf: str = pool.alloc(cap_n)
|
||
if nbuf is None:
|
||
VLogger.error("--traceback: DIFile 路径缓冲分配失败,终止编译", "DWARF")
|
||
return 1
|
||
if slen > 0:
|
||
string.strncpy(nbuf, src, slen)
|
||
nbuf[slen] = '\0'
|
||
if slen > 0 and nbuf[0] != '/' and not (slen >= 2 and nbuf[1] == ':'):
|
||
# 相对路径 → 前置当前工作目录。用 w32file 低层调用(同 Repl.vp),
|
||
# 不经 os._mbuddy:编译器进程未必初始化过那个内存管理器。
|
||
CwdBuf: bytes = pool.alloc(4112)
|
||
if CwdBuf is not None:
|
||
CwdBuf[0] = '\0'
|
||
nc: ULONG = w32file.GetCurrentDirectoryA(ULONG(4111), CwdBuf)
|
||
if nc > 0:
|
||
# 防御:缓冲区不足时 GetCurrentDirectoryA 的写入内容未定义,强制补 NUL
|
||
CwdBuf[4110] = '\0'
|
||
viperlib.snprintf(nbuf, cap_n, "%s/%s", CwdBuf, src)
|
||
# 归一所有反斜杠(CWD 段同样可能含 '\')
|
||
flen: sizet = string.strlen(nbuf)
|
||
ni: sizet = 0
|
||
for ni in range(flen):
|
||
if nbuf[ni] == '\\':
|
||
nbuf[ni] = '/'
|
||
# filename 取整条路径;directory 另存其目录前缀(两段各自 NUL 结尾,互不污染)
|
||
fname: str = nbuf
|
||
directory: str = ""
|
||
slash: str = string.strrchr(nbuf, '/')
|
||
if slash is not None:
|
||
dlen: sizet = string.strlen(nbuf) - string.strlen(slash + 1) - 1
|
||
dirbuf: str = pool.alloc(dlen + 1)
|
||
if dirbuf is not None:
|
||
string.strncpy(dirbuf, nbuf, dlen)
|
||
dirbuf[dlen] = '\0'
|
||
directory = dirbuf
|
||
dsize: sizet = string.strlen(fname) + string.strlen(directory) + 96
|
||
dbuf: str = pool.alloc(dsize)
|
||
if dbuf is None:
|
||
VLogger.error("--traceback: DIFile 节点缓冲分配失败,终止编译", "DWARF")
|
||
return 1
|
||
viperlib.snprintf(dbuf, dsize, "!DIFile(filename: \"%s\", directory: \"%s\")", fname, directory)
|
||
fid: int = llvmlite.module_add_di_node(mod, pool, dbuf)
|
||
if fid < 0:
|
||
VLogger.error("--traceback: DIFile 元数据节点分配失败,终止编译", "DWARF")
|
||
return 1
|
||
_g_file_id = fid
|
||
# types: !{ null } placeholder list, then DISubroutineType referencing it
|
||
nid: int = llvmlite.module_add_di_node(mod, pool, "!{ null }")
|
||
if nid < 0:
|
||
VLogger.error("--traceback: DISubroutineType 类型表分配失败,终止编译", "DWARF")
|
||
return 1
|
||
_g_null_id = nid
|
||
tbuf: str = pool.alloc(64)
|
||
if tbuf is None:
|
||
VLogger.error("--traceback: DISubroutineType 缓冲分配失败,终止编译", "DWARF")
|
||
return 1
|
||
viperlib.snprintf(tbuf, 64, "!DISubroutineType(types: !%d)", _g_null_id)
|
||
tid: int = llvmlite.module_add_di_node(mod, pool, tbuf)
|
||
if tid < 0:
|
||
VLogger.error("--traceback: DISubroutineType 元数据节点分配失败,终止编译", "DWARF")
|
||
return 1
|
||
_g_subtype_id = tid
|
||
cbuf: str = pool.alloc(256)
|
||
if cbuf is None:
|
||
VLogger.error("--traceback: DICompileUnit 缓冲分配失败,终止编译", "DWARF")
|
||
return 1
|
||
viperlib.snprintf(cbuf, 256,
|
||
"distinct !DICompileUnit(language: DW_LANG_C99, file: !%d, producer: \"TPC\", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug)",
|
||
_g_file_id)
|
||
cid: int = llvmlite.module_add_di_node(mod, pool, cbuf)
|
||
if cid < 0:
|
||
VLogger.error("--traceback: DICompileUnit 元数据节点分配失败,终止编译", "DWARF")
|
||
return 1
|
||
_g_cu_id = cid
|
||
return 0
|
||
|
||
|
||
# ============================================================
|
||
# _LocRefAt - read a cached DILocation ref string pointer
|
||
# ============================================================
|
||
def _LocRefAt(slot: int) -> str:
|
||
slotp: str | t.CPtr = (str | t.CPtr)(uint64(_g_loc_ref) + sizet(slot) * 8)
|
||
r: str = slotp[0]
|
||
return r
|
||
|
||
|
||
# ============================================================
|
||
# _EnsureLocation - DILocation ref for (sp, line, col), created + cached once
|
||
# ============================================================
|
||
def _EnsureLocation(pool: memhub.MemBuddy*, sp: int, line: int, col: int) -> str:
|
||
if line <= 0:
|
||
return _g_cur_entry_ref
|
||
c: int = col
|
||
if c <= 0:
|
||
c = 1
|
||
if _g_loc_used is None or _g_mod is None:
|
||
return None
|
||
h: uint64 = (uint64(sp) * 1000003 + uint64(line) * 31 + uint64(c)) & uint64(DBG_LOC_SLOTS - 1)
|
||
pi: int = 0
|
||
while pi < DBG_LOC_PROBE:
|
||
slot: int = int((h + uint64(pi)) & uint64(DBG_LOC_SLOTS - 1))
|
||
if _g_loc_used[slot] == 0:
|
||
break
|
||
kbase: int = slot * DBG_LOC_KEY_STRIDE
|
||
if int(_g_loc_key[kbase]) == sp and int(_g_loc_key[kbase + 1]) == line \
|
||
and int(_g_loc_key[kbase + 2]) == c:
|
||
return _LocRefAt(slot)
|
||
pi += 1
|
||
lbuf: str = pool.alloc(96)
|
||
if lbuf is None:
|
||
return None
|
||
viperlib.snprintf(lbuf, 96, "!DILocation(line: %d, column: %d, scope: !%d)", line, c, sp)
|
||
lid: int = llvmlite.module_add_di_node(_g_mod, pool, lbuf)
|
||
if lid < 0:
|
||
VLogger.error("--traceback: DILocation 元数据节点分配失败,终止编译", "DWARF")
|
||
return None
|
||
lref: str = _RefOf(pool, lid)
|
||
if lref is None:
|
||
VLogger.error("--traceback: DILocation 引用缓冲分配失败,终止编译", "DWARF")
|
||
return None
|
||
if pi < DBG_LOC_PROBE:
|
||
slot2: int = int((h + uint64(pi)) & uint64(DBG_LOC_SLOTS - 1))
|
||
kbase2: int = slot2 * DBG_LOC_KEY_STRIDE
|
||
_g_loc_key[kbase2] = sizet(sp)
|
||
_g_loc_key[kbase2 + 1] = sizet(line)
|
||
_g_loc_key[kbase2 + 2] = sizet(c)
|
||
rslot: str | t.CPtr = (str | t.CPtr)(uint64(_g_loc_ref) + sizet(slot2) * 8)
|
||
rslot[0] = lref
|
||
_g_loc_used[slot2] = 1
|
||
return lref
|
||
|
||
|
||
# ============================================================
|
||
# PushFunction - create the DISubprogram for one define
|
||
# ============================================================
|
||
def PushFunction(pool: memhub.MemBuddy*, builder: llvmlite.IRBuilder*,
|
||
func: llvmlite.Function*, line: int, col: int) -> int:
|
||
"""Attach a DISubprogram to one define and set the builder's entry DILocation.
|
||
|
||
Returns 1 when pushed (caller must call PopFunction), 0 when DI is disabled
|
||
or not applicable. Every instruction emitted afterwards on `builder` carries
|
||
", !dbg !N" until the next SetStatement.
|
||
"""
|
||
global _g_cur_sp, _g_cur_entry_ref, _g_cur_builder, _g_depth
|
||
if _g_enabled == 0:
|
||
return 0
|
||
if pool is None or builder is None or func is None or _g_mod is None:
|
||
return 0
|
||
if _g_depth >= DBG_STACK_MAX:
|
||
VLogger.error("--traceback: DWARF 函数嵌套深度超上限,终止编译", "DWARF")
|
||
return 0
|
||
if _EnsureModuleNodes(pool) != 0:
|
||
return 0
|
||
name: str = llvmlite.function_get_name(func)
|
||
if name is None:
|
||
VLogger.error("--traceback: 函数名为空,无法发射 DISubprogram,终止编译", "DWARF")
|
||
return 0
|
||
dline: int = line
|
||
if dline <= 0:
|
||
dline = 1
|
||
dcol: int = col
|
||
if dcol <= 0:
|
||
dcol = 1
|
||
ssize: sizet = string.strlen(name) + 320
|
||
spbuf: str = pool.alloc(ssize)
|
||
if spbuf is None:
|
||
VLogger.error("--traceback: DISubprogram 缓冲分配失败,终止编译", "DWARF")
|
||
return 0
|
||
viperlib.snprintf(spbuf, ssize,
|
||
"distinct !DISubprogram(name: \"%s\", scope: !%d, file: !%d, type: !%d, line: %d, scopeLine: %d, unit: !%d, spFlags: DISPFlagDefinition)",
|
||
name, _g_file_id, _g_file_id, _g_subtype_id, dline, dline, _g_cu_id)
|
||
sp_id: int = llvmlite.module_add_di_node(_g_mod, pool, spbuf)
|
||
if sp_id < 0:
|
||
VLogger.error("--traceback: DISubprogram 元数据节点分配失败,终止编译", "DWARF")
|
||
return 0
|
||
sp_ref: str = _RefOf(pool, sp_id)
|
||
if sp_ref is None:
|
||
VLogger.error("--traceback: DISubprogram 引用缓冲分配失败,终止编译", "DWARF")
|
||
return 0
|
||
llvmlite.function_set_dbg(func, sp_ref)
|
||
# save the enclosing function's DI context (LIFO), then switch to this one
|
||
_g_stk_sp[_g_depth] = sizet(_g_cur_sp + 1)
|
||
rslot: str | t.CPtr = (str | t.CPtr)(uint64(_g_stk_ref) + sizet(_g_depth) * 8)
|
||
rslot[0] = _g_cur_entry_ref
|
||
bslot: str | t.CPtr = (str | t.CPtr)(uint64(_g_stk_bld) + sizet(_g_depth) * 8)
|
||
bslot[0] = _g_cur_builder
|
||
_g_depth += 1
|
||
_g_cur_sp = sp_id
|
||
_g_cur_builder = builder
|
||
entry_ref: str = _EnsureLocation(pool, sp_id, dline, dcol)
|
||
if entry_ref is None:
|
||
VLogger.error("--traceback: 入口 DILocation 生成失败,终止编译", "DWARF")
|
||
return 0
|
||
_g_cur_entry_ref = entry_ref
|
||
llvmlite.builder_set_debug_location(builder, entry_ref)
|
||
return 1
|
||
|
||
|
||
# ============================================================
|
||
# PopFunction - restore the enclosing function's DI context
|
||
# ============================================================
|
||
def PopFunction(builder: llvmlite.IRBuilder*) -> int:
|
||
global _g_cur_sp, _g_cur_entry_ref, _g_cur_builder, _g_depth
|
||
if _g_enabled == 0:
|
||
return 0
|
||
if _g_depth <= 0:
|
||
return 0
|
||
_g_depth -= 1
|
||
_g_cur_sp = int(_g_stk_sp[_g_depth]) - 1
|
||
rslot: str | t.CPtr = (str | t.CPtr)(uint64(_g_stk_ref) + sizet(_g_depth) * 8)
|
||
_g_cur_entry_ref = rslot[0]
|
||
bslot: str | t.CPtr = (str | t.CPtr)(uint64(_g_stk_bld) + sizet(_g_depth) * 8)
|
||
_g_cur_builder = (llvmlite.IRBuilder*)(bslot[0])
|
||
if builder is not None:
|
||
llvmlite.builder_clear_debug_location(builder)
|
||
return 0
|
||
|
||
|
||
# ============================================================
|
||
# SetStatement - point the current builder at a statement DILocation
|
||
# ============================================================
|
||
def SetStatement(pool: memhub.MemBuddy*, builder: llvmlite.IRBuilder*,
|
||
line: int, col: int) -> int:
|
||
"""Update the builder's DILocation to the current statement (line precision).
|
||
|
||
No-op outside a DI-attached define (module-level code / synthetic defines),
|
||
so instructions outside a function body never reference a function's scope.
|
||
"""
|
||
if _g_enabled == 0 or pool is None or builder is None:
|
||
return 0
|
||
if _g_cur_sp < 0:
|
||
return 0
|
||
ref: str = _EnsureLocation(pool, _g_cur_sp, line, col)
|
||
if ref is None:
|
||
return 0
|
||
llvmlite.builder_set_debug_location(builder, ref)
|
||
return 1
|
||
|
||
|
||
# ============================================================
|
||
# _ModuleHasDefine - does the module emit any define (IsDeclared == 0)?
|
||
# ============================================================
|
||
def _ModuleHasDefine(mod: llvmlite.LLVMModule*) -> int:
|
||
if mod is None:
|
||
return 0
|
||
cur: llvmlite.Function* = mod.FuncHead
|
||
steps: int = 0
|
||
while cur is not None:
|
||
steps += 1
|
||
if steps > 100000:
|
||
break
|
||
if llvmlite.function_is_declared(cur) == 0:
|
||
return 1
|
||
cur = llvmlite.function_get_next(cur)
|
||
return 0
|
||
|
||
|
||
# ============================================================
|
||
# Finalize - register !llvm.dbg.cu / !llvm.module.flags before dump_ir
|
||
# ============================================================
|
||
def Finalize(pool: memhub.MemBuddy*) -> int:
|
||
"""Module-level DI tail; idempotent per module, no-op when no SP was emitted."""
|
||
global _g_finalized
|
||
if _g_enabled == 0:
|
||
return 0
|
||
if _g_finalized != 0:
|
||
return 0
|
||
mod: llvmlite.LLVMModule* = _g_mod
|
||
if mod is None or pool is None:
|
||
return 0
|
||
_g_finalized = 1
|
||
# Self-check (mirrors TPC Phase2Translator.py:3444): a module that emits a
|
||
# define but carries no DI at all loses line info for its frames.
|
||
if mod.DIMetaCount == 0 and _ModuleHasDefine(mod) != 0:
|
||
VLogger.warning("--traceback: 本模块发射了 define 但 IR 未携带 DWARF (!llvm.dbg.cu)——该模块帧在 Ctrl+C 栈里将只显示地址", "DWARF")
|
||
if _g_cu_id < 0:
|
||
return 0
|
||
cu_ref: str = _RefOf(pool, _g_cu_id)
|
||
if cu_ref is None:
|
||
VLogger.error("--traceback: DICompileUnit 引用缓冲分配失败,终止编译", "DWARF")
|
||
return 1
|
||
llvmlite.module_add_named_metadata(mod, pool, "llvm.dbg.cu", cu_ref)
|
||
fbuf: str = pool.alloc(64)
|
||
if fbuf is None:
|
||
VLogger.error("--traceback: 模块级调试标志缓冲分配失败,终止编译", "DWARF")
|
||
return 1
|
||
viperlib.snprintf(fbuf, 64, "!{i32 2, !\"Debug Info Version\", i32 3}")
|
||
flags_id: int = llvmlite.module_add_di_node(mod, pool, fbuf)
|
||
if flags_id < 0:
|
||
VLogger.error("--traceback: llvm.module.flags 元数据节点分配失败,终止编译", "DWARF")
|
||
return 1
|
||
fl_ref: str = _RefOf(pool, flags_id)
|
||
if fl_ref is None:
|
||
VLogger.error("--traceback: llvm.module.flags 引用缓冲分配失败,终止编译", "DWARF")
|
||
return 1
|
||
llvmlite.module_add_named_metadata(mod, pool, "llvm.module.flags", fl_ref)
|
||
return 0
|