From 7bd4cda5be9f57d03bc00a20bdf62733a10be32e Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Sat, 3 Oct 2026 12:17:39 +0800 Subject: [PATCH] =?UTF-8?q?fix(llvmlite):=20=E6=89=93=E5=8D=B0=E7=AB=AF?= =?UTF-8?q?=E8=B7=B3=E8=BF=87=E8=A2=AB=E5=90=8C=E6=A8=A1=E5=9D=97=E5=AE=9A?= =?UTF-8?q?=E4=B9=89=E5=8F=96=E4=BB=A3=E7=9A=84=20external=20global?= =?UTF-8?q?=EF=BC=88=E6=B6=88=E9=99=A4=20redefinition=20of=20global?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 模块内不变量:同一符号名不得同时打印 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 去重同构)。 --- llvmlite/__module.vp | 47 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/llvmlite/__module.vp b/llvmlite/__module.vp index d0863af..7452f29 100644 --- a/llvmlite/__module.vp +++ b/llvmlite/__module.vp @@ -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 '@.'"。 +# 触发场景:循环 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*): """打印单个全局变量: @ = [linkage] [unnamed_addr] [constant] """