diff --git a/lib/core/Handles/HandlesAssign.py b/lib/core/Handles/HandlesAssign.py index 0810640..9e64ad4 100644 --- a/lib/core/Handles/HandlesAssign.py +++ b/lib/core/Handles/HandlesAssign.py @@ -1765,6 +1765,30 @@ class AssignHandle(BaseHandle): return Gen.builder.gep(VarPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"arr_start_{VarName}") return None + def _BuildStringPtrInitializer(self, Gen: "Translator.LlvmGen", VarName: str, str_value: str) -> ir.Constant: + """模块级 `X: str = "字面量"` 全局的初始化器:指向常量字符数组**首元素** + + 字符串常量以 `@X_str`(internal global [N x i8])承载,重复调用复用同一 + 全局;返回 `getelementptr([N x i8], [N x i8]* @X_str, i32 0, i32 0)`。 + + 注意:**不能**用 `ir.Constant(ptr_type, str_gv)` —— 该写法把整个全局定义 + 内联成初始化器(渲染出 `@X = global i8* @X_str = internal global [...]` + 这种非法 IR),必须用 `ir.Constant.gep` 取首元素地址(与 import 侧 + HandlesImports._EmitExternalGlobalDeclLlvm 的字符串分支同口径)。 + """ + str_bytes: bytes = (str_value + '\x00').encode('utf-8') + arr_type: ir.ArrayType = ir.ArrayType(ir.IntType(8), len(str_bytes)) + str_gv_name: str = VarName + '_str' + str_gv: ir.GlobalVariable + if str_gv_name not in Gen.module.globals: + str_gv = ir.GlobalVariable(Gen.module, arr_type, name=str_gv_name) + str_gv.initializer = ir.Constant(arr_type, bytearray(str_bytes)) + str_gv.linkage = 'internal' + else: + str_gv = Gen.module.globals[str_gv_name] + zero: ir.Constant = ir.Constant(ir.IntType(32), 0) + return ir.Constant.gep(str_gv, [zero, zero]) + def _EmitGlobalAnnAssignLlvm(self, Node: ast.AnnAssign, Gen: "Translator.LlvmGen") -> None: # 内建定长数组构造子 array 的注解校验(误用即 fail-fast,含文件:行:列): # 模块级全局注解不经过 ResolveAnnotationType,故在此显式校验。 @@ -1930,9 +1954,19 @@ class AssignHandle(BaseHandle): # 声明/定义靠 initializer 区分:external 声明 initializer 恒为 None。 if isinstance(existing_gv, ir.GlobalVariable) and getattr(existing_gv, 'initializer', None) is None: try: - existing_gv.linkage = 'common' - if Node.value is None or (isinstance(Node.value, ast.Constant) and Node.value.value is None): - existing_gv.initializer = ir.Constant(existing_gv.type.pointee, None) + if (isinstance(Node.value, ast.Constant) and isinstance(Node.value.value, str) + and isinstance(getattr(existing_gv, 'value_type', None), ir.PointerType)): + # 字符串字面量全局:补"指向常量数组首元素"的初始化器。 + # **不能**设 common —— LLVM 要求 common 全局的初始化器必须是 + # 零值(verifier: "'common' global must have a zero + # initializer!"),配非空初值直接非法;保持默认 external + # 强定义即可跨模块共享(Config.BackendTarget / + # _inc_bin_suffix 都在运行时被赋值/读取,符号必须唯一且可见)。 + existing_gv.initializer = self._BuildStringPtrInitializer(Gen, VarName, Node.value.value) + else: + existing_gv.linkage = 'common' + if Node.value is None or (isinstance(Node.value, ast.Constant) and Node.value.value is None): + existing_gv.initializer = ir.Constant(existing_gv.type.pointee, None) Gen.variables[VarName] = existing_gv except Exception: pass @@ -1962,26 +1996,17 @@ class AssignHandle(BaseHandle): Gen.global_var_ptr_element[VarName] = True if Node.value: if isinstance(Node.value, ast.Constant) and isinstance(Node.value.value, str) and isinstance(VarType, ir.PointerType): - str_val: str = Node.value.value + '\x00' - str_bytes: bytes = str_val.encode('utf-8') - arr_type: ir.ArrayType = ir.ArrayType(ir.IntType(8), len(str_bytes)) - str_gv_name: str = VarName + '_str' - str_gv: ir.GlobalVariable - if str_gv_name not in Gen.module.globals: - str_gv = ir.GlobalVariable(Gen.module, arr_type, name=str_gv_name) - str_gv.initializer = ir.Constant(arr_type, bytearray(str_bytes)) - str_gv.linkage = 'internal' - else: - str_gv = Gen.module.globals[str_gv_name] - ptr_type: ir.PointerType = ir.PointerType(ir.IntType(8)) - ptr_gv: ir.GlobalVariable - if VarName not in Gen.module.globals: - ptr_gv = ir.GlobalVariable(Gen.module, ptr_type, name=VarName) - ptr_gv.initializer = ir.Constant(ptr_type, str_gv) - ptr_gv.linkage = 'internal' - else: - ptr_gv = Gen.module.globals[VarName] - Gen.variables[VarName] = ptr_gv + # 字符串字面量全局:初始化器 = 指向 @{VarName}_str 常量数组首元素 + # 的 GEP。此前这里在创建 GlobalVar(上方数行)之后又查 + # `VarName not in Gen.module.globals` —— 该条件恒为假(GlobalVar + # 刚被登记),于是永远走 else 分支、**从不写初始化器**:全工程模块级 + # `str = "字面量"` 全局退化成无初值的声明,第二遍再被升级成 + # `common global i8* null`,字符串常量沦为无人引用的 @NAME_str。 + # 只读常量(如 BuildPipeline.MLIR_OPT_CMD)在 mlir 后端 + # strlen(NULL) 直接崩(ASan 0x0)。 + if getattr(GlobalVar, 'initializer', None) is None: + GlobalVar.initializer = self._BuildStringPtrInitializer(Gen, VarName, Node.value.value) + Gen.variables[VarName] = GlobalVar elif isinstance(VarType, ir.PointerType) and isinstance(VarType.pointee, ir.FunctionType) and isinstance(Node.value, ast.Name): # 函数指针赋值:f3: t.Callable[[int], int] = f RefName: str = Node.value.id