feat(global): 支持模块级符号地址初始化器
新增 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 都是负数/取反字面量)
This commit is contained in:
1 parent
5993affd9c
commit
12b15958c6
1 file changed
+52
-7
@@ -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.
|
||||
|
||||
Reference in new issue
Block a user