From 12b15958c6841e6a1bfda11ef2d0fd3ea8ed4ed5 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Wed, 7 Oct 2026 14:54:44 +0800 Subject: [PATCH] =?UTF-8?q?feat(global):=20=E6=94=AF=E6=8C=81=E6=A8=A1?= =?UTF-8?q?=E5=9D=97=E7=BA=A7=E7=AC=A6=E5=8F=B7=E5=9C=B0=E5=9D=80=E5=88=9D?= =?UTF-8?q?=E5=A7=8B=E5=8C=96=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增 init_kind=5(符号地址):分类阶段识别 UnaryOp(AddrOf, Name),不再把它 误送进整数常量提取器;发射阶段取模块作用域里该全局的引用文本(@mangled / @mangled 带引号两种形式)作为初始化器,MLIR 层渲染为 llvm.mlir.addressof。 类型/操作数/引用目标不合法时按 fail-fast 报错。 复现:_v: int = 1 / _p: rawptr = &_v 修复前报 CDefine value extraction failed(该分支原假设所有 UnaryOp 都是负数/取反字面量) --- App/lib/core/Gen/TranslatorGenMixin.vp | 59 +++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 7 deletions(-) diff --git a/App/lib/core/Gen/TranslatorGenMixin.vp b/App/lib/core/Gen/TranslatorGenMixin.vp index 6a0d8f2..8035e4c 100644 --- a/App/lib/core/Gen/TranslatorGenMixin.vp +++ b/App/lib/core/Gen/TranslatorGenMixin.vp @@ -495,7 +495,8 @@ novirtual class TranslatorGenMixin: resolved_stg_entry: GenTypes.StructEntry* = None # Object-class global: matching StructEntry (for vtable init) init_val: int64 = 0 init_fval: double = 0.0 # Value when init_kind==4 (float literal) - init_kind: int = 0 # 0=none, 1=int, 2=list, 3=str, 4=float + init_kind: int = 0 # 0=none, 1=int, 2=list, 3=str, 4=float, 5=symbol address + init_sym_node: ast.AST* = None # Operand of `= &global` (init_kind==5) init_str_val: str = None init_list_node: ast.List* = None # Explicit `= None` init keeps lazy-initialization pointer semantics: the global must stay @@ -571,9 +572,16 @@ novirtual class TranslatorGenMixin: init_kind = 4 elif val_kind == ast.ASTKind.UnaryOp: # Negative/bitwise-invert literal: the AST is UnaryOp(USub, Constant); unhandled - # it would compile to zeroinitializer and lose the initial value. - init_val = self.Gen.AssignGen.extract_cdefine_int_value(aa.value) - init_kind = 1 + # it would compile to zeroinitializer and lose the initial value. `&global` + # (UnaryOp(AddrOf, Name)) is a symbol-address initializer instead and must not be + # fed to the integer constant extractor. + uop_g: ast.UnaryOp* = ast.UnaryOp*(aa.value) + if uop_g is not None and uop_g.op == ast.OpKind.AddrOf: + init_sym_node = uop_g.operand + init_kind = 5 + else: + init_val = self.Gen.AssignGen.extract_cdefine_int_value(aa.value) + init_kind = 1 elif val_kind == ast.ASTKind.List: init_list_node = ast.List*(aa.value) init_kind = 2 @@ -603,9 +611,15 @@ novirtual class TranslatorGenMixin: init_kind = 4 var_ty = mlirlite.Double(pool) elif val_kind2 == ast.ASTKind.UnaryOp: - # Negative literal (same as the AnnAssign branch above): UnaryOp(USub, Constant) - init_val = self.Gen.AssignGen.extract_cdefine_int_value(asgn.value) - init_kind = 1 + # Negative literal (same as the AnnAssign branch above): UnaryOp(USub, Constant). + # `= &global` is a symbol-address initializer instead (see the AnnAssign branch). + uop_g2: ast.UnaryOp* = ast.UnaryOp*(asgn.value) + if uop_g2 is not None and uop_g2.op == ast.OpKind.AddrOf: + init_sym_node = uop_g2.operand + init_kind = 5 + else: + init_val = self.Gen.AssignGen.extract_cdefine_int_value(asgn.value) + init_kind = 1 elif val_kind2 == ast.ASTKind.List: init_list_node = ast.List*(asgn.value) init_kind = 2 @@ -729,6 +743,37 @@ novirtual class TranslatorGenMixin: fc_g: mlirlite.Value* = mlirlite.ConstFloat(pool, var_ty, init_fval) if fc_g is not None and fc_g.Name is not None: gv.Initializer = fc_g.Name else: self.Gen.TypeGenErr.fatal_error(node, f"failed to build the float initializer of module-level variable '{var_name}'", "TypeError") + elif init_kind == 5: + # Symbol-address initializer (`= &global`): the referenced global's mangled symbol is + # emitted as `@name` (LLVM-quoted when required); the MLIR layer renders it as + # llvm.mlir.addressof. Only a pointer-typed global can hold an address. + is_ptr_g: int = 0 + match var_ty: + case mlirlite.LLVMType.Ptr(_): + is_ptr_g = 1 + case _: + pass + if is_ptr_g == 0: + self.Gen.TypeGenErr.fatal_error(node, f"module-level variable '{var_name}' is initialized with an address-of expression, but its type is not a pointer (add a pointer annotation or drop the '&')", "TypeError") + return 0 + if init_sym_node is None or init_sym_node.kind() != ast.ASTKind.Name: + self.Gen.TypeGenErr.fatal_error(node, f"module-level variable '{var_name}' is initialized with an address-of expression whose operand is not a variable name", "TypeError") + return 0 + sym_nm: ast.Name* = ast.Name*(init_sym_node) + sym_val: mlirlite.Value* = None + if sym_nm.id is not None: sym_val = self.Gen.VarGen.lookup_module_var(trans.SymTab, sym_nm.id) + if sym_val is None or sym_val.Name is None: + self.Gen.TypeGenErr.fatal_error(node, f"module-level variable '{var_name}' is initialized with &{sym_nm.id}, but '{sym_nm.id}' is not a module-level variable declared before this line", "NameError") + return 0 + sym_buf: str = pool.alloc(256) + if sym_buf is None: return 0 + # The module-scope entry already holds the LLVM reference text of that global + # (`@mangled` or `@"mangled"`), so it is used verbatim; only a bare name (no '@') needs + # the reference prefix added here. + if sym_val.Name[0] == '@': viperlib.snprintf(sym_buf, 256, "%s", sym_val.Name) + elif self.Gen.ClassGenVTable._vtable_name_needs_quote(sym_val.Name) != 0: viperlib.snprintf(sym_buf, 256, "@\"%s\"", sym_val.Name) + else: viperlib.snprintf(sym_buf, 256, "@%s", sym_val.Name) + gv.Initializer = sym_buf else: # Use zeroinitializer (valid for pointer/integer/aggregate types). Object-class globals # with storage get &@storage below; `= None` lazy globals still need it to stay complete.