fix(codegen): keep module-level DefineT initializers
This commit is contained in:
1 parent
fde6571a3b
commit
79d53e691c
1 file changed
+45
-5
@@ -478,6 +478,30 @@ novirtual class TranslatorGenMixin:
|
||||
return 0
|
||||
|
||||
|
||||
# _module_init_from_cdefine - resolve a module-level initializer that is a bare DefineT name.
|
||||
# Without this the initializer is silently dropped and the global becomes zero/BSS
|
||||
# (e.g. `_text_mode: int = TEXT_MODE_MANAGED` ran as 0).
|
||||
def _module_init_from_cdefine(self, name: str, kind_out: int*, val_out: int64*, fval_out: double*, sval_out: str*) -> int:
|
||||
"""Fill the initializer kind/value from a DefineT name; 1 when resolved, 0 otherwise."""
|
||||
if name is None: return 0
|
||||
cv: int64 = self.Gen.TypeGenCDef.lookup_cdefine_constant(name)
|
||||
if self.Gen.TypeGenCDef.is_cdefine_found() == 0: return 0
|
||||
if self.Gen.TypeGenCDef.is_cdefine_str() != 0:
|
||||
sv: str = self.Gen.TypeGenCDef.lookup_cdefine_string(name)
|
||||
if sv is None: return 0
|
||||
if sval_out is not None: sval_out[0] = sv
|
||||
if kind_out is not None: kind_out[0] = 3
|
||||
return 1
|
||||
if self.Gen.TypeGenCDef.is_cdefine_double() != 0:
|
||||
dv: double = self.Gen.TypeGenCDef.lookup_cdefine_double(name)
|
||||
if fval_out is not None: fval_out[0] = dv
|
||||
# Kind 6: float value already known, so emission must not re-read a source literal.
|
||||
if kind_out is not None: kind_out[0] = 6
|
||||
return 1
|
||||
if val_out is not None: val_out[0] = cv
|
||||
if kind_out is not None: kind_out[0] = 1
|
||||
return 1
|
||||
|
||||
def handle_module_level_var(self, trans: HT.Translator*, node: ast.AST*) -> int:
|
||||
"""Handle a module-level variable declaration by creating its global."""
|
||||
pool: memhub.MemBuddy* = trans.Pool
|
||||
@@ -627,6 +651,12 @@ novirtual class TranslatorGenMixin:
|
||||
elif val_kind == ast.ASTKind.List:
|
||||
init_list_node = ast.List*(aa.value)
|
||||
init_kind = 2
|
||||
elif val_kind == ast.ASTKind.Name:
|
||||
# DefineT reference (`g: int = SOME_DEFINE`): resolve at compile time, else the
|
||||
# global is created without an initializer and silently becomes 0/BSS.
|
||||
nv_g: ast.Name* = ast.Name*(aa.value)
|
||||
if nv_g is not None and nv_g.id is not None:
|
||||
self._module_init_from_cdefine(nv_g.id, &init_kind, &init_val, &init_fval, &init_str_val)
|
||||
elif k == ast.ASTKind.Assign:
|
||||
asgn: ast.Assign* = ast.Assign*(node)
|
||||
if asgn is None or asgn.targets is None: return 0
|
||||
@@ -675,6 +705,14 @@ novirtual class TranslatorGenMixin:
|
||||
elif val_kind2 == ast.ASTKind.List:
|
||||
init_list_node = ast.List*(asgn.value)
|
||||
init_kind = 2
|
||||
elif val_kind2 == ast.ASTKind.Name:
|
||||
# DefineT reference without an annotation; the define's kind decides the
|
||||
# inferred type (int -> i32, float -> double, string -> str pointer).
|
||||
nv_g2: ast.Name* = ast.Name*(asgn.value)
|
||||
if nv_g2 is not None and nv_g2.id is not None:
|
||||
self._module_init_from_cdefine(nv_g2.id, &init_kind, &init_val, &init_fval, &init_str_val)
|
||||
if init_kind == 6: var_ty = mlirlite.Double(pool)
|
||||
elif init_kind == 3: var_ty = mlirlite.Ptr(pool, mlirlite.Int8(pool))
|
||||
elif val_kind2 == ast.ASTKind.Attribute:
|
||||
# Module-level re-export alias (e.g. `_read32 = types._read32`): the RHS is an
|
||||
# entity reference with no value semantics, so emit no LLVM global (same as __all__).
|
||||
@@ -688,7 +726,8 @@ novirtual class TranslatorGenMixin:
|
||||
|
||||
# Float literal init (init_kind==4): re-read the value from source by name instead of the
|
||||
# AST float_val (which pool ops may overwrite); also validate that the annotation is float.
|
||||
if init_kind == 4:
|
||||
# init_kind==6 is a float already resolved from a DefineT, so no source re-read applies.
|
||||
if init_kind == 4 or init_kind == 6:
|
||||
is_fty_g: int = 0
|
||||
match var_ty:
|
||||
case mlirlite.LLVMType.Float(_):
|
||||
@@ -698,9 +737,10 @@ novirtual class TranslatorGenMixin:
|
||||
if is_fty_g == 0:
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"module-level variable '{var_name}' is initialized with a float literal, but its annotation is not a float type", "TypeError")
|
||||
return 0
|
||||
if self.Gen.AssignGen._recover_float_literal(var_name, &init_fval, 0) != 1:
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"failed to recover the initializer value of module-level float variable '{var_name}' from the source file", "InternalCompilerError")
|
||||
return 0
|
||||
if init_kind == 4:
|
||||
if self.Gen.AssignGen._recover_float_literal(var_name, &init_fval, 0) != 1:
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"failed to recover the initializer value of module-level float variable '{var_name}' from the source file", "InternalCompilerError")
|
||||
return 0
|
||||
|
||||
# Check whether it is already registered
|
||||
existing: mlirlite.Value* = self.Gen.VarGen.lookup_module_var(trans.SymTab, var_name)
|
||||
@@ -799,7 +839,7 @@ novirtual class TranslatorGenMixin:
|
||||
str_init: str = self._build_string_ptr_initializer(pool, mod, var_name, init_str_val)
|
||||
if str_init is not None: gv.Initializer = str_init
|
||||
else: self.Gen.TypeGenErr.fatal_error(node, f"failed to build the initializer of module-level variable '{var_name}'", "TypeError")
|
||||
elif init_kind == 4:
|
||||
elif init_kind == 4 or init_kind == 6:
|
||||
# Float initializer: LLVM float constants must be written as bit-pattern text
|
||||
# (0x%016llx / 0x%08x); decimal text has ulp errors, and omitting this zeroes the global.
|
||||
fc_g: mlirlite.Value* = mlirlite.ConstFloat(pool, var_ty, init_fval)
|
||||
|
||||
Reference in new issue
Block a user