fix(llvmlite): 打印端跳过被同模块定义取代的 external global(消除 redefinition of global)

模块内不变量:同一符号名不得同时打印 external 声明与定义,否则 llc 报 redefinition of global(SysLibTest os/__init__ 的 _mbuddy:循环 import 使 LoadDepVpiIntoModule 把本模块自身 vpi 注入自身 → 先发 external,handle_module_level_var 再发定义)。新增 _module_has_initializer_global:OUTPUT_FULL/STUB/TEXT 三模式对无初值 GV,若模块内存在同名带初值定义则跳过。只处理本模块内同名声明+定义,依赖模块的合法 external(本模块无同名定义)一律保留,不做跨模块去重(与 TransPyC Phase2Translator 合并期 external 去重同构)。
This commit is contained in:
TermiNexus committed 2026-10-03 12:17:39 +08:00
1 parent 7f3b3dea1a
commit 7bd4cda5be
1 file changed
+43 -4
+43 -4
View File
@@ -396,6 +396,11 @@ class LLVMModule:
stdio.printf("[IR-DUMP] 链表成环: module globals stub(GlobalCount=%zu,dump 终止)\n",
self.GlobalCount)
stdlib.exit(1)
# 模块内不变量:同名 external 声明若已被同名定义取代则跳过,
# 避免 stub 输出出现同一符号两行(见 _module_has_initializer_global)。
if gv.Initializer is None and _module_has_initializer_global(self, gv.Name) != 0:
gv = gv.Next
continue
_print_global_stub(buf, size, gv, pool)
_append_cstr(buf, size, "\n")
gv = gv.Next
@@ -409,10 +414,15 @@ class LLVMModule:
stdio.printf("[IR-DUMP] 链表成环: module globals(GlobalCount=%zu,dump 终止)\n",
self.GlobalCount)
stdlib.exit(1)
if mode == OUTPUT_TEXT and gv.Initializer is None:
gv = gv.Next
gv_idx += 1
continue
# text 模式跳过无初值的全局变量(纯声明);
# full 模式亦跳过"已被同名定义取代"的纯声明(见
# _module_has_initializer_global)——否则单模块 IR 同名声明+定义
# 并存,llc 报 "redefinition of global"。
if gv.Initializer is None:
if mode == OUTPUT_TEXT or _module_has_initializer_global(self, gv.Name) != 0:
gv = gv.Next
gv_idx += 1
continue
_print_global(buf, size, gv, pool)
_append_cstr(buf, size, "\n")
gv = gv.Next
@@ -818,6 +828,35 @@ def LLVMModulePrint(buf: str, size: sizet,
# ============================================================
# 全局变量打印
# ============================================================
# _module_has_initializer_global - 模块内是否存在同名"定义"全局(带初值)
#
# 模块内不变量:同一符号名不得同时出现 external 声明与定义,否则 llc 报
# "redefinition of global '@<sha1>.<name>'"。
# 触发场景:循环 import(如 os/__init__ 同时 import os._win32/os._posix,二者又
# 导入包 os ⇒ imported_modules 含 "os" 自身)使**本模块自己的 .vpi** 被当作依赖
# 注入;VpiReader._inject_global_variable_declare 先在本模块加一个同名 external
# 声明全局,随后 handle_module_level_var 再发射同名定义 ⇒ 单模块 IR 同名冲突。
# 打印端按"同名 + 有初值"判定并跳过纯声明,保证单模块 IR 自足合法(对齐旧编译器
# TransPyC/Phase2Translator 合并期的 external 去重:同名的 external 声明被定义取代)。
# 只跳过"无初值且有同名初值定义"的声明;依赖模块的合法 external(本模块无同名
# 定义)一律保留,不做跨模块去重。
# ============================================================
def _module_has_initializer_global(mod: rawptr[LLVMModule], name: str) -> int:
if mod is None or name is None:
return 0
cur: rawptr[GlobalVariable] = mod.GlobalHead
steps: sizet = 0
while cur is not None:
steps += 1
if steps > IR_DUMP_CHAIN_LIMIT:
break
if cur.Name is not None and cur.Initializer is not None:
if string.strcmp(cur.Name, name) == 0:
return 1
cur = cur.Next
return 0
def _print_global(buf: str, size: sizet,
gv: rawptr[GlobalVariable], pool: memhub.MemBuddy*):
"""打印单个全局变量: @<name> = [linkage] [unnamed_addr] [constant] <ty> <init>"""