fix(defines): isolate same-name cross-module DefineT lookups
This commit is contained in:
1 parent
ebb291daeb
commit
a2e9b1848e
10 files changed
+284
-186
No files matched your search
@@ -2309,12 +2309,12 @@ def _vpi_register_typedef_closure(pool: memhub.MemBuddy*, import_mods: str, temp
|
||||
if neg_r != 0: fv_r = -fv_r
|
||||
# 浮点宽度同样由声明注解裁决(与定义方同一套),
|
||||
# 否则 `define PI: float = ...` 的使用方会把 f32 当 double
|
||||
GenApi.register_cdefine_double(pool, cdef_t.id, fv_r, GenApi.cdefine_decl_float_bits(pool, aa_r.annotation))
|
||||
GenApi.register_cdefine_double(pool, cdef_t.id, fv_r, GenApi.cdefine_decl_float_bits(pool, aa_r.annotation), sha1_r)
|
||||
elif cn_v.const_kind == ast.CONST_INT:
|
||||
cdef_val: int64 = GenApi.extract_cdefine_int_value(vnode_r)
|
||||
# 位宽与定义方同一套裁决(注解 → 右侧强转 → 值的最小可存宽度),
|
||||
# 否则使用方拿 bits=0 只能兜底,跨模块位宽会与定义方不一致
|
||||
GenApi.register_cdefine_constant(pool, cdef_t.id, cdef_val, GenApi.cdefine_decl_bits(pool, aa_r.annotation, vnode_r))
|
||||
GenApi.register_cdefine_constant(pool, cdef_t.id, cdef_val, GenApi.cdefine_decl_bits(pool, aa_r.annotation, vnode_r), sha1_r)
|
||||
# recurse into child imports (cycle guarded by the visited marks)
|
||||
if sub_imports[0] != '\0': _vpi_register_typedef_closure(pool, sub_imports, temp_dir, depth + 1)
|
||||
stdlib.free(sub_imports)
|
||||
@@ -3241,6 +3241,11 @@ def _ParseVpiIntoModuleImpl(pool: memhub.MemBuddy*, mod: mlirlite.LLVMModule*, v
|
||||
if pre_skip_fn_declares == 0:
|
||||
_inject_method_declare(pool, mod, m_fd1, cls_name_v1, trans, src_sha1, imported_modules, from_imports, i32_ty, i8_ptr_ty, funcs_ptr, max_funcs)
|
||||
|
||||
def_mod: str = src_sha1
|
||||
if trans is not None and trans.ModuleSha1 is not None and string.strcmp(trans.ModuleSha1, src_sha1) == 0:
|
||||
# This vpi is the current module's own: keep its defines reachable by bare name.
|
||||
def_mod = None
|
||||
|
||||
i: sizet
|
||||
for i in range(int(n)):
|
||||
child: ast.AST* = ch.get(i)
|
||||
@@ -3308,11 +3313,11 @@ def _ParseVpiIntoModuleImpl(pool: memhub.MemBuddy*, mod: mlirlite.LLVMModule*, v
|
||||
# Float DefineT (e.g. FRAGMENTATION_THRESHOLD: t.DefineT = 0.7): register via
|
||||
# register_cdefine_double (integer extraction would fail fast).
|
||||
# 注解声明 float 时带上 f32 种类(与定义方同一套裁决)。
|
||||
GenApi.register_cdefine_double(pool, cdef_tgt.id, cdef_float_val, GenApi.cdefine_decl_float_bits(pool, aa.annotation))
|
||||
GenApi.register_cdefine_double(pool, cdef_tgt.id, cdef_float_val, GenApi.cdefine_decl_float_bits(pool, aa.annotation), def_mod)
|
||||
elif cdef_is_str == 0:
|
||||
cdef_val: int64 = GenApi.extract_cdefine_int_value(vnode)
|
||||
# 位宽与定义方同一套裁决(注解 → 右侧强转 → 值的最小可存宽度)
|
||||
GenApi.register_cdefine_constant(pool, cdef_tgt.id, cdef_val, GenApi.cdefine_decl_bits(pool, aa.annotation, vnode))
|
||||
GenApi.register_cdefine_constant(pool, cdef_tgt.id, cdef_val, GenApi.cdefine_decl_bits(pool, aa.annotation, vnode), def_mod)
|
||||
else:
|
||||
_inject_global_variable_declare(pool, mod, aa, trans, stub_imported_modules, stub_from_imports, i32_ty, i8_ptr_ty, src_sha1)
|
||||
continue
|
||||
|
||||
@@ -350,46 +350,50 @@ novirtual class ExprGenAttr(ExprGenBase.ExprGenBase):
|
||||
# first check whether it is an ordinary variable (higher priority than module attr)
|
||||
ma_is_var: mlirlite.Value* = self.Gen.VarGen.lookup_var(trans.SymTab, nm_ma.id)
|
||||
if ma_is_var is None:
|
||||
# first check whether it is a DefineT compile-time constant (e.g. ast.CONST_INT /
|
||||
# win32base.INVALID_HANDLE_VALUE); such constants require a cross-module .vp/.vpi search
|
||||
cdef_ma_val: int64 = self.Gen.TypeGenCDef.lookup_cdefine_constant(at.attr)
|
||||
cd_local: int = self.Gen.TypeGenCDef.is_cdefine_found()
|
||||
if cd_local == 0:
|
||||
# determine the real module name: prefer resolving the alias from _from_imports,
|
||||
# whose entries look like "local_name:real_module" (e.g. win32base:win32.win32base)
|
||||
real_mod_name: str = nm_ma.id
|
||||
if trans._from_imports is not None:
|
||||
resolved_mod: str = self.Gen.ImportsGen.lookup_from_import(trans._from_imports, nm_ma.id, 0)
|
||||
if resolved_mod is not None:
|
||||
# copy the module name into a new buffer (truncate at space, null, or ':')
|
||||
rm_len: sizet = 0
|
||||
while resolved_mod[rm_len] != ' ' and resolved_mod[rm_len] != '\0' and resolved_mod[rm_len] != ':': rm_len += 1
|
||||
rm_buf: str = pool.alloc(rm_len + 1)
|
||||
if rm_buf is not None:
|
||||
for rm_i in range(int(rm_len)): rm_buf[rm_i] = resolved_mod[rm_i]
|
||||
rm_buf[rm_len] = '\0'
|
||||
real_mod_name = rm_buf
|
||||
# even when _from_imports is None (e.g. a plain `import ast`), still attempt the
|
||||
# cross-module DefineT lookup, else ast.CONST_INT is misread as @CONST_INT (undefined).
|
||||
if real_mod_name is not None:
|
||||
ma_fi_len: sizet = string.strlen(at.attr) + string.strlen(real_mod_name) + 2
|
||||
ma_fi: str = pool.alloc(ma_fi_len)
|
||||
if ma_fi is not None:
|
||||
viperlib.snprintf(ma_fi, ma_fi_len, "%s:%s", at.attr, real_mod_name)
|
||||
cdef_ma_val = self.Gen.ExprGenCdef._lookup_cross_module_cdefine(pool, at.attr, ma_fi)
|
||||
# Resolve the receiver module BEFORE any lookup. A module-qualified access
|
||||
# must never fall back to the bare table: that is how `b.VALUE` used to
|
||||
# return `a.VALUE` when both modules define VALUE.
|
||||
real_mod_name: str = None
|
||||
if trans._from_imports is not None:
|
||||
resolved_mod: str = self.Gen.ImportsGen.lookup_from_import(trans._from_imports, nm_ma.id, 0)
|
||||
if resolved_mod is not None:
|
||||
rm_len: sizet = 0
|
||||
while resolved_mod[rm_len] != ' ' and resolved_mod[rm_len] != '\0' and resolved_mod[rm_len] != ':': rm_len += 1
|
||||
rm_buf: str = pool.alloc(rm_len + 1)
|
||||
if rm_buf is not None:
|
||||
for rm_i in range(int(rm_len)): rm_buf[rm_i] = resolved_mod[rm_i]
|
||||
rm_buf[rm_len] = '\0'
|
||||
real_mod_name = rm_buf
|
||||
if real_mod_name is None and trans._imported_modules is not None:
|
||||
if self.Gen.ImportsGen.is_module_imported(trans._imported_modules, nm_ma.id) != 0: real_mod_name = nm_ma.id
|
||||
if real_mod_name is None and self._lookup_module_sha1(nm_ma.id) is not None: real_mod_name = nm_ma.id
|
||||
|
||||
cd_mod: str = None
|
||||
cdef_ma_val: int64 = 0
|
||||
if real_mod_name is not None:
|
||||
# Qualified access: look up only this module's define.
|
||||
ma_fi_len: sizet = string.strlen(at.attr) + string.strlen(real_mod_name) + 2
|
||||
ma_fi: str = pool.alloc(ma_fi_len)
|
||||
if ma_fi is not None:
|
||||
viperlib.snprintf(ma_fi, ma_fi_len, "%s:%s", at.attr, real_mod_name)
|
||||
cdef_ma_val = self.Gen.ExprGenCdef._lookup_cross_module_cdefine(pool, at.attr, ma_fi)
|
||||
if self.Gen.TypeGenCDef.is_cdefine_found() != 0:
|
||||
cd_mod = self.Gen.TypeGenCDef.get_last_cdefine_module()
|
||||
else:
|
||||
# Non-module receiver (class/enum qualified field): bare table only.
|
||||
cdef_ma_val = self.Gen.TypeGenCDef.lookup_cdefine_constant(at.attr)
|
||||
if self.Gen.TypeGenCDef.is_cdefine_found() != 0:
|
||||
# cross-module string DefineT (e.g. pyzlib.ZLIB_VERSION = "1.3.2")
|
||||
# → string global constant (test_pyzlib.vp: ver = pyzlib.ZLIB_VERSION)
|
||||
if self.Gen.TypeGenCDef.is_cdefine_str() != 0:
|
||||
cdef_str_v: str = self.Gen.TypeGenCDef.lookup_cdefine_string(at.attr)
|
||||
cdef_str_v: str = self.Gen.TypeGenCDef.lookup_cdefine_string(at.attr, cd_mod)
|
||||
if cdef_str_v is not None: return self.Gen.ExprGenConst.create_global_string(builder, pool, mod, cdef_str_v, trans)
|
||||
# cross-module float DefineT (e.g. vipermath.U_M_PI) → float constant
|
||||
dchk_ma: double = self.Gen.TypeGenCDef.lookup_cdefine_double(at.attr)
|
||||
dchk_ma: double = self.Gen.TypeGenCDef.lookup_cdefine_double(at.attr, cd_mod)
|
||||
# f32 声明的常量直接出 f32 常量(否则 f32 字面量会被提升成 double)
|
||||
if self.Gen.TypeGenCDef.is_cdefine_double() != 0:
|
||||
if self.Gen.TypeGenCDef.is_cdefine_float32() != 0: return mlirlite.ConstFloat(pool, mlirlite.Float(pool), dchk_ma)
|
||||
return mlirlite.ConstFloat(pool, mlirlite.Double(pool), dchk_ma)
|
||||
return self.Gen.ExprGenCdef._const_int_for_cdefine(pool, at.attr, cdef_ma_val)
|
||||
return self.Gen.ExprGenCdef._const_int_for_cdefine(pool, at.attr, cdef_ma_val, cd_mod)
|
||||
# check whether nm_ma.id.at.attr is an imported submodule (e.g. win32.win32file);
|
||||
# for a submodule do not create a global, let the nested attribute path handle it
|
||||
is_submod: int = 0
|
||||
@@ -493,23 +497,25 @@ novirtual class ExprGenAttr(ExprGenBase.ExprGenBase):
|
||||
case _:
|
||||
pass
|
||||
return mlirlite.build_load(builder, load_ty_nested, gv_ref_nested)
|
||||
# global not found: try a DefineT constant lookup; for nested module attributes
|
||||
# like win32.win32base.INVALID_HANDLE_VALUE, resolve the DefineT from the .vpi
|
||||
cdef_val_nested: int64 = self.Gen.TypeGenCDef.lookup_cdefine_constant(at.attr)
|
||||
if self.Gen.TypeGenCDef.is_cdefine_found() == 0:
|
||||
# build a temporary from_imports "attr:module" for the cross-module lookup
|
||||
tmp_fi_len: sizet = string.strlen(at.attr) + string.strlen(qual_buf) + 2
|
||||
tmp_fi: str = pool.alloc(tmp_fi_len)
|
||||
if tmp_fi is not None:
|
||||
viperlib.snprintf(tmp_fi, tmp_fi_len, "%s:%s", at.attr, qual_buf)
|
||||
cdef_val_nested = self.Gen.ExprGenCdef._lookup_cross_module_cdefine(pool, at.attr, tmp_fi)
|
||||
# DefineT lookup for a nested module attribute: the qualified
|
||||
# module is known, so never consult the bare table here.
|
||||
cdef_val_nested: int64 = 0
|
||||
tmp_fi_len: sizet = string.strlen(at.attr) + string.strlen(qual_buf) + 2
|
||||
tmp_fi: str = pool.alloc(tmp_fi_len)
|
||||
if tmp_fi is not None:
|
||||
viperlib.snprintf(tmp_fi, tmp_fi_len, "%s:%s", at.attr, qual_buf)
|
||||
cdef_val_nested = self.Gen.ExprGenCdef._lookup_cross_module_cdefine(pool, at.attr, tmp_fi)
|
||||
if self.Gen.TypeGenCDef.is_cdefine_found() != 0:
|
||||
nst_mod: str = self.Gen.TypeGenCDef.get_last_cdefine_module()
|
||||
# cross-module float DefineT → float constant (f32 声明直接出 f32)
|
||||
dchk_nst: double = self.Gen.TypeGenCDef.lookup_cdefine_double(at.attr)
|
||||
dchk_nst: double = self.Gen.TypeGenCDef.lookup_cdefine_double(at.attr, nst_mod)
|
||||
if self.Gen.TypeGenCDef.is_cdefine_double() != 0:
|
||||
if self.Gen.TypeGenCDef.is_cdefine_float32() != 0: return mlirlite.ConstFloat(pool, mlirlite.Float(pool), dchk_nst)
|
||||
return mlirlite.ConstFloat(pool, mlirlite.Double(pool), dchk_nst)
|
||||
return self.Gen.ExprGenCdef._const_int_for_cdefine(pool, at.attr, cdef_val_nested)
|
||||
if self.Gen.TypeGenCDef.is_cdefine_str() != 0:
|
||||
nst_s: str = self.Gen.TypeGenCDef.lookup_cdefine_string(at.attr, nst_mod)
|
||||
if nst_s is not None: return self.Gen.ExprGenConst.create_global_string(builder, pool, mod, nst_s, trans)
|
||||
return self.Gen.ExprGenCdef._const_int_for_cdefine(pool, at.attr, cdef_val_nested, nst_mod)
|
||||
# DefineT not found: fail-fast and stop compiling (no more undefined global
|
||||
# references, which would make llc report "use of undefined value").
|
||||
if self.Gen.ExprGenCdef._is_cdefine_name_pattern(at.attr) != 0:
|
||||
|
||||
@@ -127,15 +127,13 @@ novirtual class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
# clear the found flag at entry so every early return reports "not found",
|
||||
# avoiding a stale success flag left over from a previous recursive call.
|
||||
self.Gen.TypeGenCDef.set_cdefine_found(0)
|
||||
self.Gen.TypeGenCDef.set_last_cdefine_module(None)
|
||||
if name is None: return -1
|
||||
if from_imports is None: from_imports = ""
|
||||
|
||||
# 1. resolve the module name for `name` from from_imports; try exact match first
|
||||
# (allow_star_fallback=0) so a star import cannot mislead DefineT constants.
|
||||
mod_name_raw: str = self.Gen.ImportsGen.lookup_from_import(from_imports, name, 0)
|
||||
if mod_name_raw is None:
|
||||
# exact match failed: try the star import fallback
|
||||
mod_name_raw = self.Gen.ImportsGen.lookup_from_import(from_imports, name, 1)
|
||||
# 1. resolve the module name for `name` from from_imports. The LAST matching entry
|
||||
# wins (Python name binding), so `from a import X; from b import X` resolves to b.
|
||||
mod_name_raw: str = self.Gen.ImportsGen.lookup_from_import_last(from_imports, name)
|
||||
|
||||
# truncate module name at NUL: lookup_from_import returns a pointer into from_imports
|
||||
# (not NUL-terminated); match _lookup_sha1_from_modname_raw (space/colon/NUL delimited).
|
||||
@@ -153,6 +151,10 @@ novirtual class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
|
||||
# cross-module DefineT cache (perm_pool, reused across files): key = "name@srcModule"
|
||||
# keeps modules isolated so same-name constants from different modules do not cross.
|
||||
# Local table entries are keyed by the source module SHA1 (stronger than a name alias).
|
||||
sha1_pre: str = None
|
||||
if mod_name_raw is not None: sha1_pre = self.Gen.CallGenBase._lookup_sha1_from_modname_raw(pool, mod_name_raw)
|
||||
mod_key: str = sha1_pre if sha1_pre is not None else base_mod
|
||||
xkey_buf: str = None
|
||||
if base_mod is not None:
|
||||
xk_len: sizet = string.strlen(name) + string.strlen(base_mod) + 2
|
||||
@@ -161,55 +163,27 @@ novirtual class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
viperlib.snprintf(xkey_buf, xk_len, "%s@%s", name, base_mod)
|
||||
xval: str = self.Gen.TypeGenCDef.lookup_xmod_cdefine(xkey_buf)
|
||||
if self.Gen.TypeGenCDef.is_cdefine_found() != 0:
|
||||
if self.Gen.TypeGenCDef.is_cdefine_str() != 0: self.Gen.TypeGenCDef.register_cdefine_string(pool, name, xval)
|
||||
self.Gen.TypeGenCDef.set_last_cdefine_module(mod_key)
|
||||
if self.Gen.TypeGenCDef.is_cdefine_str() != 0: self.Gen.TypeGenCDef.register_cdefine_string(pool, name, xval, mod_key)
|
||||
elif self.Gen.TypeGenCDef.is_cdefine_double() != 0:
|
||||
xd_v: double = string.atof(xval)
|
||||
# 缓存里带宽度种类(f32 声明 → 1),否则使用方会把 f32 常量当 double 物化
|
||||
xd_f32: int = self.Gen.TypeGenCDef.is_cdefine_float32()
|
||||
self.Gen.TypeGenCDef.register_cdefine_double(pool, name, xd_v, xd_f32)
|
||||
self.Gen.TypeGenCDef.register_cdefine_double(pool, name, xd_v, xd_f32, mod_key)
|
||||
else:
|
||||
xv_i: int64 = string.atoll(xval)
|
||||
self.Gen.TypeGenCDef.register_cdefine_constant(pool, name, xv_i)
|
||||
self.Gen.TypeGenCDef.register_cdefine_constant(pool, name, xv_i, 0, mod_key)
|
||||
return string.atoll(xval)
|
||||
|
||||
# 2. from_imports failed: fall back to the imported_modules walk (step 9.6);
|
||||
# a star fallback may name a wrong module, so keep scanning imported_modules.
|
||||
# 2. No module could be resolved from from_imports. Do not guess by scanning every
|
||||
# imported module: with same-name defines in several modules that picks an arbitrary
|
||||
# value. Callers must qualify (a.X / b.X) or use an explicit from-import.
|
||||
if mod_name_raw is None:
|
||||
# from_imports matched nothing (exact and star both failed):
|
||||
# go straight to the imported_modules walk (step 9.6).
|
||||
if imported_modules is None: return -1
|
||||
# skip reading the from_imports module; go directly to the step 9.6 walk.
|
||||
# result_found=0 skips steps 3-9 and jumps to 9.6.
|
||||
self.Gen.TypeGenCDef.set_cdefine_found(0)
|
||||
# iterate imported_modules directly
|
||||
im_len: sizet = string.strlen(imported_modules)
|
||||
im_ci: sizet = 0
|
||||
while im_ci < im_len:
|
||||
while im_ci < im_len and imported_modules[im_ci] == ' ': im_ci += 1
|
||||
if im_ci >= im_len: break
|
||||
im_start: sizet = im_ci
|
||||
while im_ci < im_len and imported_modules[im_ci] != ' ': im_ci += 1
|
||||
im_end: sizet = im_ci
|
||||
im_nlen: sizet = im_end - im_start
|
||||
if im_nlen > 0 and im_nlen < 256:
|
||||
im_buf: str = pool.alloc(im_nlen + 1)
|
||||
if im_buf is not None:
|
||||
for mk in range(int(im_nlen)):
|
||||
im_buf[mk] = imported_modules[im_start + mk]
|
||||
im_buf[im_nlen] = '\0'
|
||||
sub_fi: str = pool.alloc(im_nlen + 3)
|
||||
if sub_fi is not None:
|
||||
sub_fi[0] = '*'
|
||||
sub_fi[1] = ':'
|
||||
for mk2 in range(int(im_nlen)):
|
||||
sub_fi[2 + mk2] = im_buf[mk2]
|
||||
sub_fi[2 + im_nlen] = '\0'
|
||||
sub_val: int64 = self._lookup_cross_module_cdefine(pool, name, sub_fi, None, depth + 1, node)
|
||||
if self.Gen.TypeGenCDef.is_cdefine_found() != 0: return sub_val
|
||||
return -1
|
||||
|
||||
# truncate module name, strip leading dots, find SHA1 via exact+suffix (shared logic)
|
||||
sha1: str = self.Gen.CallGenBase._lookup_sha1_from_modname_raw(pool, mod_name_raw)
|
||||
sha1: str = sha1_pre
|
||||
if sha1 is None: sha1 = self.Gen.CallGenBase._lookup_sha1_from_modname_raw(pool, mod_name_raw)
|
||||
if sha1 is None: return -1
|
||||
|
||||
# 5. get temp_dir
|
||||
@@ -487,7 +461,8 @@ novirtual class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
if is_str_val != 0:
|
||||
# string DefineT (e.g. ZLIB_VERSION = "1.3.2"): register the string value
|
||||
# (including ""), mark result_found + res_is_str so the tail skips integers.
|
||||
self.Gen.TypeGenCDef.register_cdefine_string(pool, name, val_buf)
|
||||
self.Gen.TypeGenCDef.register_cdefine_string(pool, name, val_buf, sha1)
|
||||
self.Gen.TypeGenCDef.set_last_cdefine_module(sha1)
|
||||
result_val = 0
|
||||
result_found = 1
|
||||
res_is_str = 1
|
||||
@@ -496,8 +471,10 @@ novirtual class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
if string.strcmp(val_buf, "True") == 0: lval = 1
|
||||
elif string.strcmp(val_buf, "False") == 0: lval = 0
|
||||
else:
|
||||
# name reference: look up the current DefineT table (e.g. FOREGROUND_COMBO)
|
||||
lval = self.Gen.TypeGenCDef.lookup_cdefine_constant(val_buf)
|
||||
# name reference: same source module first, then the current module
|
||||
lval = self.Gen.TypeGenCDef.lookup_cdefine_constant(val_buf, sha1)
|
||||
if self.Gen.TypeGenCDef.is_cdefine_found() == 0:
|
||||
lval = self.Gen.TypeGenCDef.lookup_cdefine_constant(val_buf)
|
||||
if self.Gen.TypeGenCDef.is_cdefine_found() == 0:
|
||||
# name not registered: cannot evaluate, skip the line
|
||||
continue
|
||||
@@ -608,7 +585,9 @@ novirtual class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
if string.strcmp(r_buf, "True") == 0: rval = 1
|
||||
elif string.strcmp(r_buf, "False") == 0: rval = 0
|
||||
else:
|
||||
rval = self.Gen.TypeGenCDef.lookup_cdefine_constant(r_buf)
|
||||
rval = self.Gen.TypeGenCDef.lookup_cdefine_constant(r_buf, sha1)
|
||||
if self.Gen.TypeGenCDef.is_cdefine_found() == 0:
|
||||
rval = self.Gen.TypeGenCDef.lookup_cdefine_constant(r_buf)
|
||||
if self.Gen.TypeGenCDef.is_cdefine_found() == 0:
|
||||
# name not registered: cannot evaluate, skip the line
|
||||
continue
|
||||
@@ -650,7 +629,8 @@ novirtual class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
# constant generation; int part serves the int path (is_cdefine_double flag).
|
||||
# 注解声明为 float 时带上 f32 种类,使用方才能直接出 f32 常量。
|
||||
res_is_f32 = self._pyi_annot_float_kind(pyi_buf, annot_start, annot_end)
|
||||
self.Gen.TypeGenCDef.register_cdefine_double(pool, name, ldbl, res_is_f32)
|
||||
self.Gen.TypeGenCDef.register_cdefine_double(pool, name, ldbl, res_is_f32, sha1)
|
||||
self.Gen.TypeGenCDef.set_last_cdefine_module(sha1)
|
||||
result_val = lval
|
||||
result_found = 1
|
||||
res_is_double = 1
|
||||
@@ -805,39 +785,14 @@ novirtual class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
|
||||
stdlib.free(pyi_buf)
|
||||
|
||||
# 9.6 star-fallback module had no match: fall back to walking imported_modules,
|
||||
# e.g. `from stdint import *` names stdint but SHARE_READ lives in `import win32.fileio`.
|
||||
if result_found == 0 and imported_modules is not None:
|
||||
im2_len: sizet = string.strlen(imported_modules)
|
||||
im2_ci: sizet = 0
|
||||
while im2_ci < im2_len and result_found == 0:
|
||||
while im2_ci < im2_len and imported_modules[im2_ci] == ' ': im2_ci += 1
|
||||
if im2_ci >= im2_len: break
|
||||
im2_start: sizet = im2_ci
|
||||
while im2_ci < im2_len and imported_modules[im2_ci] != ' ': im2_ci += 1
|
||||
im2_end: sizet = im2_ci
|
||||
im2_nlen: sizet = im2_end - im2_start
|
||||
if im2_nlen > 0 and im2_nlen < 256:
|
||||
im2_buf: str = pool.alloc(im2_nlen + 1)
|
||||
if im2_buf is not None:
|
||||
for mk3 in range(int(im2_nlen)):
|
||||
im2_buf[mk3] = imported_modules[im2_start + mk3]
|
||||
im2_buf[im2_nlen] = '\0'
|
||||
sub_fi2: str = pool.alloc(im2_nlen + 3)
|
||||
if sub_fi2 is not None:
|
||||
sub_fi2[0] = '*'
|
||||
sub_fi2[1] = ':'
|
||||
for mk4 in range(int(im2_nlen)):
|
||||
sub_fi2[2 + mk4] = im2_buf[mk4]
|
||||
sub_fi2[2 + im2_nlen] = '\0'
|
||||
sub_val2: int64 = self._lookup_cross_module_cdefine(pool, name, sub_fi2, None, depth + 1, node)
|
||||
if self.Gen.TypeGenCDef.is_cdefine_found() != 0:
|
||||
result_val = sub_val2
|
||||
result_found = 1
|
||||
# 9.6 removed: scanning every imported module for a bare define name is not isolation.
|
||||
# An unqualified name must resolve through an explicit from-import; module-qualified
|
||||
# access resolves the receiver module before lookup.
|
||||
|
||||
# 10. cache into the current module's DefineT table and the cross-module perm_pool;
|
||||
# float CDefines are already cached as double, so only integers are written here.
|
||||
if result_found != 0:
|
||||
if self.Gen.TypeGenCDef.get_last_cdefine_module() is None: self.Gen.TypeGenCDef.set_last_cdefine_module(sha1)
|
||||
if res_is_str != 0:
|
||||
# string DefineT: the value was already registered in the match loop (val_buf is
|
||||
# the hit line's content, valid across the function); only write the cross cache.
|
||||
@@ -848,7 +803,8 @@ novirtual class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
viperlib.snprintf(ckey_s, ck_len_s, "%s@%s", name, base_mod)
|
||||
self.Gen.TypeGenCDef.register_xmod_cdefine(ckey_s, val_buf, 0, 1)
|
||||
elif res_is_double == 0:
|
||||
self.Gen.TypeGenCDef.register_cdefine_constant(pool, name, result_val)
|
||||
self.Gen.TypeGenCDef.register_cdefine_constant(pool, name, result_val, 0, sha1)
|
||||
self.Gen.TypeGenCDef.set_last_cdefine_module(sha1)
|
||||
# cross-module cache (perm_pool, reused across files), integers: key matches the
|
||||
# entry query "name@srcModule" (truncated base_mod, leading dots removed).
|
||||
if base_mod is not None:
|
||||
@@ -867,7 +823,7 @@ novirtual class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
ckey2: str = pool.alloc(ck_len2)
|
||||
if ckey2 is not None:
|
||||
viperlib.snprintf(ckey2, ck_len2, "%s@%s", name, base_mod)
|
||||
dval_cc: double = self.Gen.TypeGenCDef.lookup_cdefine_double(name)
|
||||
dval_cc: double = self.Gen.TypeGenCDef.lookup_cdefine_double(name, sha1)
|
||||
if self.Gen.TypeGenCDef.is_cdefine_double() != 0:
|
||||
cbuf_d: str = pool.alloc(64)
|
||||
if cbuf_d is not None:
|
||||
@@ -893,7 +849,7 @@ novirtual class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
return has_upper
|
||||
# ============================================================
|
||||
# Translate a variable reference (Name node) -> load
|
||||
def _const_int_for_cdefine(self, pool: memhub.MemBuddy*, name: str, value: int64) -> mlirlite.Value*:
|
||||
def _const_int_for_cdefine(self, pool: memhub.MemBuddy*, name: str, value: int64, module: str = None) -> mlirlite.Value*:
|
||||
"""Materialize a DefineT integer constant as an LLVM constant (TPC TypeConvert aligned)
|
||||
|
||||
位宽优先用 define 的**已知位宽**(右侧显式强转或声明注解,见 register_cdefine_constant 的 bits);
|
||||
@@ -903,7 +859,7 @@ novirtual class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
而小值 define 说成 8/16 也在算术提升下不会溢出。
|
||||
"""
|
||||
dbits: int = 0
|
||||
if name is not None: dbits = self.Gen.TypeGenCDef.lookup_cdefine_bits(name)
|
||||
if name is not None: dbits = self.Gen.TypeGenCDef.lookup_cdefine_bits(name, module)
|
||||
if dbits == 8 or dbits == 16 or dbits == 32 or dbits == 64:
|
||||
return mlirlite.const_int(pool, dbits, self._cdefine_bits_value(value, dbits))
|
||||
# 无位宽记录(例如只从 .vpi 跨模块引入、未登记 bits)→ 按**推断位宽**物化:
|
||||
|
||||
@@ -77,13 +77,14 @@ novirtual class ExprGenName(ExprGenBase.ExprGenBase):
|
||||
if self.Gen.VarGen.lookup_var(trans.SymTab, nm_id) is None:
|
||||
cdef_val: int64 = self.Gen.ExprGenCdef._lookup_cross_module_cdefine(pool, nm_id, trans._from_imports, trans._imported_modules, 0, node)
|
||||
if self.Gen.TypeGenCDef.is_cdefine_found() != 0:
|
||||
xmod: str = self.Gen.TypeGenCDef.get_last_cdefine_module()
|
||||
if self.Gen.TypeGenCDef.is_cdefine_str() != 0:
|
||||
cdef_sv2: str = self.Gen.TypeGenCDef.lookup_cdefine_string(nm_id)
|
||||
cdef_sv2: str = self.Gen.TypeGenCDef.lookup_cdefine_string(nm_id, xmod)
|
||||
if cdef_sv2 is not None: return self.Gen.ExprGenConst.create_global_string(builder, pool, mod, cdef_sv2, trans)
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"DefineT string value missing: {nm_id}", "InternalCompilerError")
|
||||
# Cross-module float DefineT is cached as double; return a float constant
|
||||
# rather than a truncated integer.
|
||||
dchk_nm: double = self.Gen.TypeGenCDef.lookup_cdefine_double(nm_id)
|
||||
dchk_nm: double = self.Gen.TypeGenCDef.lookup_cdefine_double(nm_id, xmod)
|
||||
# 同本模块路径:f32 声明的常量直接出 f32 常量(跨模块缓存已带宽度种类)。
|
||||
if self.Gen.TypeGenCDef.is_cdefine_double() != 0:
|
||||
if self.Gen.TypeGenCDef.is_cdefine_float32() != 0: return mlirlite.ConstFloat(pool, mlirlite.Float(pool), dchk_nm)
|
||||
@@ -91,7 +92,7 @@ novirtual class ExprGenName(ExprGenBase.ExprGenBase):
|
||||
# Same use-site width rule (cross-module DefineT)
|
||||
uw_x: mlirlite.Value* = self.Gen.ExprGenCdef.cdefine_use_width_value(pool, node, nm_id, cdef_val, target_ty, use_ctx)
|
||||
if uw_x is not None: return uw_x
|
||||
return self.Gen.ExprGenCdef._const_int_for_cdefine(pool, nm_id, cdef_val)
|
||||
return self.Gen.ExprGenCdef._const_int_for_cdefine(pool, nm_id, cdef_val, xmod)
|
||||
|
||||
# DefineT lookup failed: from-import module-level globals (e.g. `from Phase2 import
|
||||
# PA_DEPS_MAX_STR`, an i64 global) are located by suffix after confirming the source module.
|
||||
|
||||
@@ -448,6 +448,9 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase):
|
||||
mod: mlirlite.LLVMModule* = trans.Module
|
||||
if pool is None or mod is None: return 0
|
||||
|
||||
# Pre-register this module's own DefineT constants before any signature/body is
|
||||
# translated (Translator._preregister_module_defines, before forward declarations).
|
||||
|
||||
imported_modules: str = trans._imported_modules
|
||||
from_imports: str = trans._from_imports
|
||||
funcs_ptr: GenTypes.FuncEntry* = trans._funcs
|
||||
|
||||
@@ -177,9 +177,9 @@ def is_cdefine_found() -> int:
|
||||
|
||||
|
||||
# ---------------- register_cdefine_constant (delegates to TypeGenCDef.register_cdefine_constant) ----------------
|
||||
def register_cdefine_constant(pool: memhub.MemBuddy*, name: str, value: int64, bits: int = 0):
|
||||
"""Delegate to gen.register_cdefine_constant (bits: 0=未知;8/16/32/64=已知位宽)"""
|
||||
if _g_gen is not None: _g_gen.TypeGenCDef.register_cdefine_constant(pool, name, value, bits)
|
||||
def register_cdefine_constant(pool: memhub.MemBuddy*, name: str, value: int64, bits: int = 0, module: str = None):
|
||||
"""Delegate to gen.register_cdefine_constant (bits: 0=未知;8/16/32/64=已知位宽; module: source SHA1)"""
|
||||
if _g_gen is not None: _g_gen.TypeGenCDef.register_cdefine_constant(pool, name, value, bits, module)
|
||||
|
||||
|
||||
# ---------------- cdefine_decl_bits (delegates to AssignGenMixin.cdefine_decl_bits) ----------------
|
||||
@@ -191,9 +191,9 @@ def cdefine_decl_bits(pool: memhub.MemBuddy*, annot: ast.AST*, value_node: ast.A
|
||||
|
||||
|
||||
# ---------------- register_cdefine_double (delegates to TypeGenCDef.register_cdefine_double) ----------------
|
||||
def register_cdefine_double(pool: memhub.MemBuddy*, name: str, value: double, is_f32: int = 0):
|
||||
"""Delegate to gen.register_cdefine_double (is_f32: 1=float 声明,0=double)"""
|
||||
if _g_gen is not None: _g_gen.TypeGenCDef.register_cdefine_double(pool, name, value, is_f32)
|
||||
def register_cdefine_double(pool: memhub.MemBuddy*, name: str, value: double, is_f32: int = 0, module: str = None):
|
||||
"""Delegate to gen.register_cdefine_double (is_f32: 1=float 声明,0=double; module: source SHA1)"""
|
||||
if _g_gen is not None: _g_gen.TypeGenCDef.register_cdefine_double(pool, name, value, is_f32, module)
|
||||
|
||||
|
||||
# ---------------- cdefine_decl_float_bits (delegates to AssignGenMixin.cdefine_decl_float_bits) ----------------
|
||||
@@ -204,6 +204,12 @@ def cdefine_decl_float_bits(pool: memhub.MemBuddy*, annot: ast.AST*) -> int:
|
||||
return 0
|
||||
|
||||
|
||||
# ---------------- register_cdefine_from_ast (delegates to AssignGenMixin._register_cdefine_from_value) ----------------
|
||||
def register_cdefine_from_ast(pool: memhub.MemBuddy*, name: str, val_node: ast.AST*, annot: ast.AST* = None):
|
||||
"""Evaluate and register one module-level define from its AST value."""
|
||||
if _g_gen is not None: _g_gen.AssignGen._register_cdefine_from_value(pool, name, val_node, annot)
|
||||
|
||||
|
||||
# ---------------- is_cdefine_annotation (delegates to AssignGenMixin.is_cdefine_annotation) ----------------
|
||||
def is_cdefine_annotation(annot: ast.AST*) -> int:
|
||||
"""Delegate to gen.is_cdefine_annotation"""
|
||||
|
||||
@@ -264,6 +264,46 @@ novirtual class ImportsGenMixin:
|
||||
while ci < total_len and cur[ci] != ' ': ci += 1
|
||||
return None
|
||||
|
||||
# lookup_from_import_last - like lookup_from_import, but the LAST matching entry wins
|
||||
# (Python name binding: a later from-import shadows an earlier one). Used for DefineT
|
||||
# resolution so `from a import X; from b import X` resolves to b, not a.
|
||||
def lookup_from_import_last(self, from_imports: str, name: str) -> str:
|
||||
"""Return the module of the last exact (else last star) from-import for name."""
|
||||
if name is None or from_imports is None: return None
|
||||
name_len: sizet = string.strlen(name)
|
||||
cur: str = from_imports
|
||||
ci: sizet = 0
|
||||
total_len: sizet = string.strlen(from_imports)
|
||||
last_exact: str = None
|
||||
last_star: str = None
|
||||
while ci < total_len:
|
||||
while ci < total_len and cur[ci] == ' ': ci += 1
|
||||
if ci >= total_len: break
|
||||
colon_pos: sizet = ci
|
||||
while colon_pos < total_len and cur[colon_pos] != ':' and cur[colon_pos] != ' ': colon_pos += 1
|
||||
if colon_pos >= total_len or cur[colon_pos] != ':': break
|
||||
entry_name_len: sizet = colon_pos - ci
|
||||
if entry_name_len == 1 and cur[ci] == '*':
|
||||
mod_start: sizet = colon_pos + 1
|
||||
mod_end: sizet = mod_start
|
||||
while mod_end < total_len and cur[mod_end] != ' ' and cur[mod_end] != '\0' and cur[mod_end] != ':': mod_end += 1
|
||||
if mod_end > mod_start: last_star = cur + mod_start
|
||||
elif entry_name_len == name_len:
|
||||
matched: int = 1
|
||||
for ei in range(int(name_len)):
|
||||
if cur[ci + ei] != name[ei]:
|
||||
matched = 0
|
||||
break
|
||||
if matched != 0:
|
||||
mod_start2: sizet = colon_pos + 1
|
||||
mod_end2: sizet = mod_start2
|
||||
while mod_end2 < total_len and cur[mod_end2] != ' ' and cur[mod_end2] != '\0' and cur[mod_end2] != ':': mod_end2 += 1
|
||||
if mod_end2 > mod_start2: last_exact = cur + mod_start2
|
||||
ci = colon_pos
|
||||
while ci < total_len and cur[ci] != ' ': ci += 1
|
||||
if last_exact is not None: return last_exact
|
||||
return last_star
|
||||
|
||||
# Look up a from-import name and return the module name, or None.
|
||||
# allow_star_fallback=1 permits a star-import fallback; pass 0 to disable it.
|
||||
def lookup_from_import(self, from_imports: str, name: str, allow_star_fallback: int = 1) -> str:
|
||||
|
||||
@@ -559,6 +559,9 @@ novirtual class Translator:
|
||||
GenApi.push_trace(GenApi.get_current_file(), cur_imp_lineno)
|
||||
StubMergerBuild.LoadDepVpiIntoModule(pool, mod, self._imported_modules, self._from_imports, GenApi.get_temp_dir(), self)
|
||||
GenApi.pop_trace()
|
||||
# Register the module's own DefineT constants before any class/function body is
|
||||
# translated, so a define may be used above its declaration line.
|
||||
self._preregister_module_defines(pool, tree)
|
||||
# File-level class pre-registration already ran at the top of this function.
|
||||
# Module var pre-registration + forward declarations run only in full translation.
|
||||
if self._declare_only == 0:
|
||||
@@ -720,6 +723,23 @@ novirtual class Translator:
|
||||
if erased != 0: tree.children = kept
|
||||
return erased
|
||||
|
||||
# _preregister_module_defines - evaluate/register all top-level DefineT constants early.
|
||||
# Runs in declare-only and full translation, so signatures (array sizes) and bodies that
|
||||
# appear above the define line can use it. Values stay in the current module's namespace.
|
||||
def _preregister_module_defines(self, pool: memhub.MemBuddy*, tree: ast.AST*):
|
||||
if tree is None or tree.children is None: return
|
||||
ch: list[ast.AST*]* = tree.children
|
||||
for ci in range(int(len(ch))):
|
||||
child: ast.AST* = ch.get(ci)
|
||||
if child is None or child.kind() != ast.ASTKind.AnnAssign: continue
|
||||
aa: ast.AnnAssign* = ast.AnnAssign*(child)
|
||||
if aa is None or aa.target is None or aa.value is None or aa.annotation is None: continue
|
||||
if aa.target.kind() != ast.ASTKind.Name: continue
|
||||
nm: ast.Name* = ast.Name*(aa.target)
|
||||
if nm.id is None: continue
|
||||
if GenApi.is_cdefine_annotation(aa.annotation) == 0: continue
|
||||
GenApi.register_cdefine_from_ast(pool, nm.id, aa.value, aa.annotation)
|
||||
|
||||
# Auto container visibility injection (mirrors TPC _inject_auto_imports): mark list/dict classes
|
||||
# visible so bare annotations/constructors resolve. Detects AnnAssign annotation, Call.func, Subscript.value.
|
||||
def _inject_auto_container_visibility(self, pool: memhub.MemBuddy*, tree: ast.AST*):
|
||||
|
||||
@@ -40,6 +40,9 @@ novirtual class TypeGenBase:
|
||||
|
||||
# --- Global DefineT compile-time constant table (was _g_cdefine_*) ---
|
||||
CDefineNames: list[str]*
|
||||
# Source module of each entry ("" = declared in the current module). Cross-module values
|
||||
# are only reachable through the (name, module) pair, so same-name defines stay isolated.
|
||||
CDefineMods: list[str]*
|
||||
CDefineValues: list[str]*
|
||||
# 浮点常量的**宽度种类**:1=f64(double,默认),2=f32(float);0=非浮点(整型/字符串)。
|
||||
# 判定"是不是浮点常量"一律用 `!= 0`(既有调用处口径不变),只有浮点常量物化处区分 64/32:
|
||||
@@ -61,6 +64,7 @@ novirtual class TypeGenBase:
|
||||
# 值与 CDefineValues 分开存:名字不变,值是 '\n' 连接的元素串(元素内不含换行),
|
||||
# 供 `*OTHER_LIST` 解包与后续编译期消费者读取。与 CDefineNames 同池同生命周期。
|
||||
CDefineListNames: list[str]*
|
||||
CDefineListMods: list[str]*
|
||||
CDefineListValues: list[str]*
|
||||
|
||||
# --- Cross-module DefineT lookup cache (PermPool-allocated, reused across files) ---
|
||||
@@ -70,6 +74,8 @@ novirtual class TypeGenBase:
|
||||
# 同 CDefineDoubleFlags 的编码:1=f64,2=f32,0=非浮点。
|
||||
XmodCdefDoubleFlags: list[int]*
|
||||
XmodCdefStrFlags: list[int]*
|
||||
# Module that produced the last successful cross-module DefineT hit ("" = local/unknown).
|
||||
CDefineLastModule: str
|
||||
|
||||
# --- Current module SHA1 (was _g_current_module_sha1) ---
|
||||
CurrentModuleSha1: str
|
||||
@@ -125,6 +131,7 @@ novirtual class TypeGenBase:
|
||||
self.GenericCtxStack = None
|
||||
self.GenericCtxDepth = 0
|
||||
self.CDefineNames = None
|
||||
self.CDefineMods = None
|
||||
self.CDefineValues = None
|
||||
self.CDefineDoubleFlags = None
|
||||
self.CDefineStrFlags = None
|
||||
@@ -139,6 +146,7 @@ novirtual class TypeGenBase:
|
||||
self.XmodCdefValues = None
|
||||
self.XmodCdefDoubleFlags = None
|
||||
self.XmodCdefStrFlags = None
|
||||
self.CDefineLastModule = None
|
||||
self.CurrentModuleSha1 = None
|
||||
self.CTypedefNames = None
|
||||
self.CTypedefTypeStrs = None
|
||||
|
||||
@@ -103,25 +103,51 @@ novirtual class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
if CompilerFactory.factory is not None and CompilerFactory.factory.PermPool is not None: return CompilerFactory.factory.PermPool
|
||||
return pool
|
||||
|
||||
def register_cdefine_constant(self, pool: memhub.MemBuddy*, name: str, value: int64, bits: int = 0) -> None:
|
||||
def _cdef_module_copy(self, pool: memhub.MemBuddy*, module: str) -> str:
|
||||
"""Deep-copy the source module for a table entry; None/"" -> empty (current module)."""
|
||||
if module is None or module[0] == '\0': return ""
|
||||
n: sizet = string.strlen(module)
|
||||
c: str = pool.alloc(n + 1)
|
||||
if c is None: return ""
|
||||
string.strcpy(c, module)
|
||||
return c
|
||||
|
||||
def _cdef_module_match(self, index: sizet, module: str) -> int:
|
||||
"""1 when entry index belongs to module ("" / None = the current module)."""
|
||||
if self.CDefineMods is None or index >= len(self.CDefineMods): return 0
|
||||
em: str = self.CDefineMods.get(index)
|
||||
if module is None or module[0] == '\0': return 1 if (em is None or em[0] == '\0') else 0
|
||||
if em is None or em[0] == '\0': return 0
|
||||
return 1 if string.strcmp(em, module) == 0 else 0
|
||||
|
||||
def set_last_cdefine_module(self, module: str) -> None:
|
||||
self.CDefineLastModule = module
|
||||
|
||||
def get_last_cdefine_module(self) -> str:
|
||||
return self.CDefineLastModule
|
||||
|
||||
def register_cdefine_constant(self, pool: memhub.MemBuddy*, name: str, value: int64, bits: int = 0, module: str = None) -> None:
|
||||
"""Register an integer DefineT constant; store the value as a decimal string.
|
||||
|
||||
bits: 值表达式的位宽(0=未知,按值推断;8/16/32/64 = 显式强转或声明注解给出的位宽)。
|
||||
module: source module for a cross-module value; None/"" means the current module.
|
||||
"""
|
||||
if name is None: return
|
||||
if self.CDefineNames is None:
|
||||
tp: memhub.MemBuddy* = self._cdefine_table_pool(pool)
|
||||
tn: list[str]* = list[str](tp, 64)
|
||||
tm: list[str]* = list[str](tp, 64)
|
||||
tv: list[str]* = list[str](tp, 64)
|
||||
td: list[int]* = list[int](tp, 64)
|
||||
tsf: list[int]* = list[int](tp, 64)
|
||||
tbits: list[int]* = list[int](tp, 64)
|
||||
# Table build failed (pool unusable/exhausted): report and return, never let the
|
||||
# append below hit None or an uninitialized address (would write NULL/0xCD).
|
||||
if tn is None or tv is None or td is None or tsf is None or tbits is None:
|
||||
if tn is None or tm is None or tv is None or td is None or tsf is None or tbits is None:
|
||||
self.Gen.TypeGenErr.fatal_error(None, "DefineT table allocation failed (table body pool unavailable or exhausted)", "MemoryError")
|
||||
return
|
||||
self.CDefineNames = tn
|
||||
self.CDefineMods = tm
|
||||
self.CDefineValues = tv
|
||||
self.CDefineDoubleFlags = td
|
||||
self.CDefineStrFlags = tsf
|
||||
@@ -129,7 +155,7 @@ novirtual class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
self._cdef_idx_init(tp)
|
||||
# Table-ready guard: missing/half-initialized body -> fail-fast, no garbage writes
|
||||
# (assert non-null before append).
|
||||
if self.CDefineNames is None or self.CDefineValues is None or self.CDefineDoubleFlags is None or self.CDefineStrFlags is None or self.CDefineBits is None:
|
||||
if self.CDefineNames is None or self.CDefineMods is None or self.CDefineValues is None or self.CDefineDoubleFlags is None or self.CDefineStrFlags is None or self.CDefineBits is None:
|
||||
self.Gen.TypeGenErr.fatal_error(None, "DefineT table not ready (CDefineNames/Values/Flags is empty)", "MemoryError")
|
||||
return
|
||||
name_copy: str = pool.alloc(string.strlen(name) + 1)
|
||||
@@ -138,6 +164,7 @@ novirtual class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
return
|
||||
string.strcpy(name_copy, name)
|
||||
self.CDefineNames.append(name_copy)
|
||||
self.CDefineMods.append(self._cdef_module_copy(pool, module))
|
||||
self._cdef_idx_sync_append(name_copy)
|
||||
val_buf: str = pool.alloc(32)
|
||||
if val_buf is not None:
|
||||
@@ -150,31 +177,34 @@ novirtual class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
if self.CDefineDoubleFlags is not None: self.CDefineDoubleFlags.append(0)
|
||||
if self.CDefineStrFlags is not None: self.CDefineStrFlags.append(0)
|
||||
if self.CDefineBits is not None: self.CDefineBits.append(bits)
|
||||
def register_cdefine_double(self, pool: memhub.MemBuddy*, name: str, value: double, is_f32: int = 0) -> None:
|
||||
def register_cdefine_double(self, pool: memhub.MemBuddy*, name: str, value: double, is_f32: int = 0, module: str = None) -> None:
|
||||
"""Register a float DefineT constant; store the value as %f text and flag it.
|
||||
|
||||
is_f32: 1 表示该常量声明为 32 位 float(`define PI: float = ...` / `float(...)`),
|
||||
物化时直接出 f32 常量;0(默认)表示 double。
|
||||
module: source module for a cross-module value; None/"" means the current module.
|
||||
"""
|
||||
if name is None: return
|
||||
if self.CDefineNames is None:
|
||||
tp: memhub.MemBuddy* = self._cdefine_table_pool(pool)
|
||||
tn: list[str]* = list[str](tp, 64)
|
||||
tm: list[str]* = list[str](tp, 64)
|
||||
tv: list[str]* = list[str](tp, 64)
|
||||
td: list[int]* = list[int](tp, 64)
|
||||
tsf: list[int]* = list[int](tp, 64)
|
||||
tbits: list[int]* = list[int](tp, 64)
|
||||
if tn is None or tv is None or td is None or tsf is None or tbits is None:
|
||||
if tn is None or tm is None or tv is None or td is None or tsf is None or tbits is None:
|
||||
self.Gen.TypeGenErr.fatal_error(None, "DefineT float table allocation failed (table body pool unavailable or exhausted)", "MemoryError")
|
||||
return
|
||||
self.CDefineNames = tn
|
||||
self.CDefineMods = tm
|
||||
self.CDefineValues = tv
|
||||
self.CDefineDoubleFlags = td
|
||||
self.CDefineStrFlags = tsf
|
||||
self.CDefineBits = tbits
|
||||
self._cdef_idx_init(tp)
|
||||
# Table-ready guard (same as register_cdefine_constant): assert non-null before append
|
||||
if self.CDefineNames is None or self.CDefineValues is None or self.CDefineDoubleFlags is None or self.CDefineStrFlags is None or self.CDefineBits is None:
|
||||
if self.CDefineNames is None or self.CDefineMods is None or self.CDefineValues is None or self.CDefineDoubleFlags is None or self.CDefineStrFlags is None or self.CDefineBits is None:
|
||||
self.Gen.TypeGenErr.fatal_error(None, "DefineT float table not ready (CDefineNames/Values/Flags is empty)", "MemoryError")
|
||||
return
|
||||
name_copy_d: str = pool.alloc(string.strlen(name) + 1)
|
||||
@@ -183,6 +213,7 @@ novirtual class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
return
|
||||
string.strcpy(name_copy_d, name)
|
||||
self.CDefineNames.append(name_copy_d)
|
||||
self.CDefineMods.append(self._cdef_module_copy(pool, module))
|
||||
self._cdef_idx_sync_append(name_copy_d)
|
||||
val_buf: str = pool.alloc(32)
|
||||
if val_buf is not None:
|
||||
@@ -201,8 +232,11 @@ novirtual class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
if val_buf is None:
|
||||
VLogger.error("DefineT float value buffer allocation failed", "CDEF-DBG")
|
||||
self.Gen.TypeGenErr.fatal_error(None, "DefineT float value buffer allocation failed", "MemoryError")
|
||||
def register_cdefine_string(self, pool: memhub.MemBuddy*, name: str, value: str) -> None:
|
||||
"""Register a string DefineT constant, deep-copying name and value into pool."""
|
||||
def register_cdefine_string(self, pool: memhub.MemBuddy*, name: str, value: str, module: str = None) -> None:
|
||||
"""Register a string DefineT constant, deep-copying name and value into pool.
|
||||
|
||||
module: source module for a cross-module value; None/"" means the current module.
|
||||
"""
|
||||
if pool is None or name is None: return
|
||||
if value is None:
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"DefineT string value missing: {name}", "InternalCompilerError")
|
||||
@@ -210,21 +244,23 @@ novirtual class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
if self.CDefineNames is None:
|
||||
tp: memhub.MemBuddy* = self._cdefine_table_pool(pool)
|
||||
tn: list[str]* = list[str](tp, 64)
|
||||
tm: list[str]* = list[str](tp, 64)
|
||||
tv: list[str]* = list[str](tp, 64)
|
||||
td: list[int]* = list[int](tp, 64)
|
||||
tsf: list[int]* = list[int](tp, 64)
|
||||
tbits: list[int]* = list[int](tp, 64)
|
||||
if tn is None or tv is None or td is None or tsf is None or tbits is None:
|
||||
if tn is None or tm is None or tv is None or td is None or tsf is None or tbits is None:
|
||||
self.Gen.TypeGenErr.fatal_error(None, "DefineT string table allocation failed (table body pool unavailable or exhausted)", "MemoryError")
|
||||
return
|
||||
self.CDefineNames = tn
|
||||
self.CDefineMods = tm
|
||||
self.CDefineValues = tv
|
||||
self.CDefineDoubleFlags = td
|
||||
self.CDefineStrFlags = tsf
|
||||
self.CDefineBits = tbits
|
||||
self._cdef_idx_init(tp)
|
||||
# Table-ready guard (same as register_cdefine_constant): assert non-null before append
|
||||
if self.CDefineNames is None or self.CDefineValues is None or self.CDefineDoubleFlags is None or self.CDefineStrFlags is None or self.CDefineBits is None:
|
||||
if self.CDefineNames is None or self.CDefineMods is None or self.CDefineValues is None or self.CDefineDoubleFlags is None or self.CDefineStrFlags is None or self.CDefineBits is None:
|
||||
self.Gen.TypeGenErr.fatal_error(None, "DefineT string table not ready (CDefineNames/Values/Flags is empty)", "MemoryError")
|
||||
return
|
||||
ncopy_s: str = pool.alloc(string.strlen(name) + 1)
|
||||
@@ -233,6 +269,7 @@ novirtual class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
return
|
||||
string.strcpy(ncopy_s, name)
|
||||
self.CDefineNames.append(ncopy_s)
|
||||
self.CDefineMods.append(self._cdef_module_copy(pool, module))
|
||||
self._cdef_idx_sync_append(ncopy_s)
|
||||
vlen: sizet = string.strlen(value)
|
||||
vcopy: str = pool.alloc(vlen + 1)
|
||||
@@ -248,7 +285,7 @@ novirtual class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
# Cross-module string DefineT reads call this + set_cdefine_found; missing the flag degrades to int 0 -> NULL crash.
|
||||
self.CDefineIsStr = 1
|
||||
self.CDefineFound = 1
|
||||
def register_cdefine_string_list(self, pool: memhub.MemBuddy*, name: str, joined: str) -> None:
|
||||
def register_cdefine_string_list(self, pool: memhub.MemBuddy*, name: str, joined: str, module: str = None) -> None:
|
||||
"""Register a macro-list DefineT constant (`define NAME = [...]`, '\n'-joined value).
|
||||
|
||||
The list is compile-time only: no LLVM global is created (an unannotated module-level
|
||||
@@ -260,13 +297,15 @@ novirtual class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
if tp is None:
|
||||
self.Gen.TypeGenErr.fatal_error(None, "DefineT list table pool unavailable", "MemoryError")
|
||||
return
|
||||
if self.CDefineListNames is None or self.CDefineListValues is None:
|
||||
if self.CDefineListNames is None or self.CDefineListMods is None or self.CDefineListValues is None:
|
||||
ln_l: list[str]* = list[str](tp, 16)
|
||||
lm_l: list[str]* = list[str](tp, 16)
|
||||
lv_l: list[str]* = list[str](tp, 16)
|
||||
if ln_l is None or lv_l is None:
|
||||
if ln_l is None or lm_l is None or lv_l is None:
|
||||
self.Gen.TypeGenErr.fatal_error(None, "DefineT list table allocation failed", "MemoryError")
|
||||
return
|
||||
self.CDefineListNames = ln_l
|
||||
self.CDefineListMods = lm_l
|
||||
self.CDefineListValues = lv_l
|
||||
nlen_l: sizet = string.strlen(name)
|
||||
ncopy_l: str = tp.alloc(nlen_l + 1)
|
||||
@@ -281,16 +320,18 @@ novirtual class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
return
|
||||
string.strcpy(vcopy_l, joined)
|
||||
self.CDefineListNames.append(ncopy_l)
|
||||
self.CDefineListMods.append(self._cdef_module_copy(tp, module))
|
||||
self.CDefineListValues.append(vcopy_l)
|
||||
|
||||
def lookup_cdefine_string_list(self, name: str) -> str:
|
||||
def lookup_cdefine_string_list(self, name: str, module: str = None) -> str:
|
||||
"""Return the '\n'-joined value of a macro-list DefineT constant; None if absent."""
|
||||
if name is None or self.CDefineListNames is None or self.CDefineListValues is None: return None
|
||||
if name is None or self.CDefineListNames is None or self.CDefineListMods is None or self.CDefineListValues is None: return None
|
||||
n_l: sizet = len(self.CDefineListNames)
|
||||
for i in range(int(n_l)):
|
||||
nm_l: str = self.CDefineListNames.get(sizet(i))
|
||||
if nm_l is not None and string.strcmp(nm_l, name) == 0:
|
||||
return self.CDefineListValues.get(sizet(i))
|
||||
if self._cdef_module_match(i, module) != 0:
|
||||
return self.CDefineListValues.get(sizet(i))
|
||||
return None
|
||||
|
||||
# Cross-module DefineT lookup cache (PermPool-allocated, reused across files)
|
||||
@@ -347,26 +388,34 @@ novirtual class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
self.CDefineIsDouble = int(self.XmodCdefDoubleFlags.get(i))
|
||||
return val_str
|
||||
return None
|
||||
def lookup_cdefine_constant(self, name: str) -> int64:
|
||||
"""Look up an integer DefineT constant; 64-bit exact, found flag distinguishes -1."""
|
||||
def lookup_cdefine_constant(self, name: str, module: str = None) -> int64:
|
||||
"""Look up an integer DefineT constant; 64-bit exact, found flag distinguishes -1.
|
||||
|
||||
module=None/"" matches only defines declared in the current module; a non-empty module
|
||||
matches only that source module's entry (strong cross-module isolation).
|
||||
"""
|
||||
self.CDefineFound = 0
|
||||
self.CDefineIsDouble = 0
|
||||
self.CDefineIsStr = 0
|
||||
if self.CDefineNames is None: return 0
|
||||
if self.CDefineNames is None or self.CDefineMods is None: return 0
|
||||
n: sizet = len(self.CDefineNames)
|
||||
i: sizet
|
||||
# Name-index fast path: when trusted (Built==n and name non-null) locate the single candidate
|
||||
# (== first scan hit); if unavailable fall back to the full linear scan below.
|
||||
# Name-index fast path: only for current-module (bare) lookups; a module-qualified
|
||||
# lookup must scan because the same name may exist in several modules.
|
||||
cd_start: sizet = 0
|
||||
cd_end: sizet = n
|
||||
if name is not None and self.CDefineNameIdxBuilt == int(n) and self.CDefineNameIdx is not None and self.CDefineNameIdxCap > 0:
|
||||
cd_hit: int = self._cdef_idx_find(name)
|
||||
if cd_hit < 0: return 0
|
||||
cd_start = sizet(cd_hit)
|
||||
cd_end = sizet(cd_hit + 1)
|
||||
if module is None or module[0] == '\0':
|
||||
if name is not None and self.CDefineNameIdxBuilt == int(n) and self.CDefineNameIdx is not None and self.CDefineNameIdxCap > 0:
|
||||
cd_hit: int = self._cdef_idx_find(name)
|
||||
if cd_hit < 0: return 0
|
||||
# The index points at the first same-name entry, which may belong to another
|
||||
# module; only narrow when it is a current-module entry, else scan all.
|
||||
if self._cdef_module_match(sizet(cd_hit), module) != 0:
|
||||
cd_start = sizet(cd_hit)
|
||||
cd_end = sizet(cd_hit + 1)
|
||||
for i in range(int(cd_start), int(cd_end)):
|
||||
nm: str = self.CDefineNames.get(i)
|
||||
if nm is not None and string.strcmp(nm, name) == 0:
|
||||
if nm is not None and string.strcmp(nm, name) == 0 and self._cdef_module_match(i, module) != 0:
|
||||
val_str: str = self.CDefineValues.get(i)
|
||||
if val_str is not None:
|
||||
self.CDefineFound = 1
|
||||
@@ -381,14 +430,14 @@ novirtual class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
return string.atoll(val_str)
|
||||
return string.atoll(val_str)
|
||||
return 0
|
||||
def lookup_cdefine_bits(self, name: str) -> int:
|
||||
def lookup_cdefine_bits(self, name: str, module: str = None) -> int:
|
||||
"""Look up a DefineT constant's value-expression bit width; 0 = unknown (width inferred by value).
|
||||
|
||||
同一名字可能被注册**多次**:本模块注册带位宽(如 WORD(...) 或声明注解),而 stub/.vpi
|
||||
等路径以 bits=0 注册。若用「命中即返回」,哈希索引先命中的可能是那条 0 位宽记录,
|
||||
于是已知位宽被丢掉、常量被物化成 i32。故这里**全表扫描并优先返回非 0 位宽**。
|
||||
"""
|
||||
if self.CDefineNames is None or self.CDefineBits is None or name is None: return 0
|
||||
if self.CDefineNames is None or self.CDefineMods is None or self.CDefineBits is None or name is None: return 0
|
||||
n: sizet = len(self.CDefineNames)
|
||||
# 同一名字可能被注册多次:stub/.vpi 等早期路径先注册(位宽可能未知 → 兜底值),
|
||||
# 本模块自己的 define 翻译在后(注解/强转齐全,最权威)。故取**最后**一条非零记录,
|
||||
@@ -397,31 +446,32 @@ novirtual class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
for i in range(int(n)):
|
||||
nm: str = self.CDefineNames.get(i)
|
||||
if nm is None or string.strcmp(nm, name) != 0: continue
|
||||
if self._cdef_module_match(i, module) == 0: continue
|
||||
if sizet(i) >= len(self.CDefineBits): continue
|
||||
b: int = self.CDefineBits.get(i)
|
||||
if b != 0: found = b
|
||||
return found
|
||||
def lookup_cdefine_double(self, name: str) -> double:
|
||||
def lookup_cdefine_double(self, name: str, module: str = None) -> double:
|
||||
"""Look up a DefineT constant and return its double value (float or int)."""
|
||||
self.CDefineFound = 0
|
||||
self.CDefineIsDouble = 0
|
||||
self.CDefineIsStr = 0
|
||||
if self.CDefineNames is None: return 0.0
|
||||
if self.CDefineNames is None or self.CDefineMods is None: return 0.0
|
||||
n: sizet = len(self.CDefineNames)
|
||||
i: sizet
|
||||
# Name-index fast path: when trusted (Built==n and name non-null) locate the single candidate
|
||||
# (== first scan hit); if unavailable fall back to the full linear scan below.
|
||||
cd_start: sizet = 0
|
||||
cd_end: sizet = n
|
||||
if name is not None and self.CDefineNameIdxBuilt == int(n) and self.CDefineNameIdx is not None and self.CDefineNameIdxCap > 0:
|
||||
cd_hit: int = self._cdef_idx_find(name)
|
||||
if cd_hit < 0: return 0.0
|
||||
cd_start = sizet(cd_hit)
|
||||
cd_end = sizet(cd_hit + 1)
|
||||
if module is None or module[0] == '\0':
|
||||
if name is not None and self.CDefineNameIdxBuilt == int(n) and self.CDefineNameIdx is not None and self.CDefineNameIdxCap > 0:
|
||||
cd_hit: int = self._cdef_idx_find(name)
|
||||
if cd_hit < 0: return 0.0
|
||||
if self._cdef_module_match(sizet(cd_hit), module) != 0:
|
||||
cd_start = sizet(cd_hit)
|
||||
cd_end = sizet(cd_hit + 1)
|
||||
for i in range(int(cd_start), int(cd_end)):
|
||||
nm: str = self.CDefineNames.get(i)
|
||||
# Fast path: strcmp equality implies equal first char, so skip strcmp when it differs.
|
||||
if nm is not None and nm[0] == name[0] and string.strcmp(nm, name) == 0:
|
||||
if nm is not None and nm[0] == name[0] and string.strcmp(nm, name) == 0 and self._cdef_module_match(i, module) != 0:
|
||||
val_str: str = self.CDefineValues.get(i)
|
||||
if val_str is not None:
|
||||
self.CDefineFound = 1
|
||||
@@ -436,26 +486,26 @@ novirtual class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
ret_i2: double = double(string.atoll(val_str))
|
||||
return ret_i2
|
||||
return 0.0
|
||||
def lookup_cdefine_string(self, name: str) -> str:
|
||||
def lookup_cdefine_string(self, name: str, module: str = None) -> str:
|
||||
"""Look up a string DefineT value (valid when found=1 and is_str=1)."""
|
||||
self.CDefineFound = 0
|
||||
self.CDefineIsDouble = 0
|
||||
self.CDefineIsStr = 0
|
||||
if self.CDefineNames is None: return None
|
||||
if self.CDefineNames is None or self.CDefineMods is None: return None
|
||||
n: sizet = len(self.CDefineNames)
|
||||
i: sizet
|
||||
# Name-index fast path: when trusted (Built==n and name non-null) locate the single candidate
|
||||
# (== first scan hit); if unavailable fall back to the full linear scan below.
|
||||
cd_start: sizet = 0
|
||||
cd_end: sizet = n
|
||||
if name is not None and self.CDefineNameIdxBuilt == int(n) and self.CDefineNameIdx is not None and self.CDefineNameIdxCap > 0:
|
||||
cd_hit: int = self._cdef_idx_find(name)
|
||||
if cd_hit < 0: return None
|
||||
cd_start = sizet(cd_hit)
|
||||
cd_end = sizet(cd_hit + 1)
|
||||
if module is None or module[0] == '\0':
|
||||
if name is not None and self.CDefineNameIdxBuilt == int(n) and self.CDefineNameIdx is not None and self.CDefineNameIdxCap > 0:
|
||||
cd_hit: int = self._cdef_idx_find(name)
|
||||
if cd_hit < 0: return None
|
||||
if self._cdef_module_match(sizet(cd_hit), module) != 0:
|
||||
cd_start = sizet(cd_hit)
|
||||
cd_end = sizet(cd_hit + 1)
|
||||
for i in range(int(cd_start), int(cd_end)):
|
||||
nm: str = self.CDefineNames.get(i)
|
||||
if nm is not None and string.strcmp(nm, name) == 0:
|
||||
if nm is not None and string.strcmp(nm, name) == 0 and self._cdef_module_match(i, module) != 0:
|
||||
val_str: str = self.CDefineValues.get(i)
|
||||
if val_str is not None:
|
||||
self.CDefineFound = 1
|
||||
@@ -491,6 +541,7 @@ novirtual class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
def clear_cdefine_constants(self) -> None:
|
||||
"""Clear the DefineT table body in place, keeping the PermPool table pointers."""
|
||||
if self.CDefineNames is not None: self.CDefineNames.clear()
|
||||
if self.CDefineMods is not None: self.CDefineMods.clear()
|
||||
if self.CDefineValues is not None: self.CDefineValues.clear()
|
||||
if self.CDefineDoubleFlags is not None: self.CDefineDoubleFlags.clear()
|
||||
if self.CDefineStrFlags is not None: self.CDefineStrFlags.clear()
|
||||
@@ -498,7 +549,9 @@ novirtual class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
# Macro-list table is per-file too: a stale entry would let `*NAME` resolve a list that
|
||||
# belongs to another file's compilation unit.
|
||||
if self.CDefineListNames is not None: self.CDefineListNames.clear()
|
||||
if self.CDefineListMods is not None: self.CDefineListMods.clear()
|
||||
if self.CDefineListValues is not None: self.CDefineListValues.clear()
|
||||
self.CDefineLastModule = None
|
||||
# Clear index slots (store index+1; 0=empty) and reset Built to 0 (empty table and index
|
||||
# in sync, matching a freshly built table before its first register).
|
||||
if self.CDefineNameIdx is not None and self.CDefineNameIdxCap > 0:
|
||||
|
||||
Reference in new issue
Block a user