From b859f8a136a961e247341cef3c6ce200879b39c5 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Mon, 12 Oct 2026 21:48:05 +0800 Subject: [PATCH] =?UTF-8?q?fix(gen):=20CDefine=20=E5=B8=B8=E9=87=8F?= =?UTF-8?q?=EF=BC=88=E5=90=AB=20mod.N=20=E5=B1=9E=E6=80=A7=E5=BD=A2?= =?UTF-8?q?=E6=80=81=EF=BC=89=E6=8B=93=E5=AE=BD=E6=96=B9=E5=90=91=E5=8D=95?= =?UTF-8?q?=E7=8B=AC=E5=88=A4=E5=AE=9A=E2=80=94=E2=80=94=E8=B4=9F=E5=80=BC?= =?UTF-8?q?=20sext=E3=80=81=E9=9D=9E=E8=B4=9F=20zext=EF=BC=8C=E4=BF=AE=20z?= =?UTF-8?q?lib=20=E7=AA=97=E5=8F=A3=E5=B0=BA=E5=AF=B8=E8=A2=AB=20sext=20?= =?UTF-8?q?=E6=88=90=E8=B4=9F=E6=95=B0=E4=B8=8E=20Z=5FDEFAULT=5FCOMPRESSIO?= =?UTF-8?q?N->255?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/lib/core/Gen/Expr/ExprGenOps.vp | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/App/lib/core/Gen/Expr/ExprGenOps.vp b/App/lib/core/Gen/Expr/ExprGenOps.vp index 4ebd77d..aaf6a97 100644 --- a/App/lib/core/Gen/Expr/ExprGenOps.vp +++ b/App/lib/core/Gen/Expr/ExprGenOps.vp @@ -135,6 +135,15 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase): if narrow_val is None or narrow_val.Ty is None: return 0 narrow_bits: int = self.get_llvm_type_bits(narrow_val.Ty) if narrow_bits == 1: return 1 + # 编译期 CDefine 常量(裸名 `N` 或模块属性 `mod.N`)单独判定,必须**早于**下方「i8 默认 zext」: + # · 负值 → sext(有符号语义,如 `define Z_DEFAULT_COMPRESSION = (-1)` 必须变 i32 -1,而非 255); + # · 非负 → zext(无符号位模式,如 `define WINDOW_SIZE = (1 << 15)` 必须变 32768,而非 -32768)。 + # 否则这两类常量拓宽时必有一类被弄错(i8 位型走「默认 zext」;i16 位型若判不出无符号则走 sext)。 + if narrow_node is not None: + cd_v_zw: int64 = self._cdefine_int_of(narrow_node) + if self.Gen.TypeGenCDef.is_cdefine_found() != 0: + if cd_v_zw < 0: return 0 + return 1 if narrow_bits == 8: # i8 defaults to unsigned-byte handling (systems convention), but an explicitly signed source annotation # must sext to preserve sign: `int32(v)` with v: int8 = -50 must stay -50, not become 206. @@ -154,16 +163,28 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase): # 50000 in 16 bits) is materialized as an unsigned bit pattern -> zext. Covered by # _node_type_unsigned below (which delegates to _cdefine_unsigned_bitpattern); keep return 0. return 0 + # _cdefine_int_of - 取节点引用的 CDefine 常量值。支持两种引用形态: + # · 裸名 `N` + # · 模块属性 `mod.N`(跨模块经 .vpi 注册;常量名就是 at.attr) + # 未命中时 `Gen.TypeGenCDef.is_cdefine_found()` 为 0 —— 本函数每次都刷新该标志(空名也走一次 lookup)。 + def _cdefine_int_of(self, node: ast.AST*) -> int64: + """CDefine integer value referenced by node (bare name or `mod.N`); check is_cdefine_found().""" + nm_cd: str = "" + if node is not None: + if node.kind() == ast.ASTKind.Name: + n_cd: ast.Name* = ast.Name*(node) + if n_cd.id is not None: nm_cd = n_cd.id + elif node.kind() == ast.ASTKind.Attribute: + a_cd: ast.Attribute* = ast.Attribute*(node) + if a_cd.attr is not None: nm_cd = a_cd.attr + return self.Gen.TypeGenCDef.lookup_cdefine_constant(nm_cd) # _cdefine_unsigned_bitpattern - 1 if node 是**非负 CDefine 常量**,且按它的最小可容纳位宽 W_min # 取无符号位模式时 high bit 已置位(如 50000 → W_min=16 → 0xC350)。规范:非负数按无符号位模式 # 物化、负值按有符号解释(Debugger/define-constants.md §7.2)。这类常量在**宽化**与**比较** # (for-range 边界)时必须按无符号处理,否则 32768..65535 的常量会被读成负数(range 变 0 次)。 def _cdefine_unsigned_bitpattern(self, node: ast.AST*) -> int: """1 = node is a non-negative CDefine whose minimal width's high bit is set; else 0.""" - if node is None or node.kind() != ast.ASTKind.Name: return 0 - nm_cd: ast.Name* = ast.Name*(node) - if nm_cd.id is None: return 0 - v_cd: int64 = self.Gen.TypeGenCDef.lookup_cdefine_constant(nm_cd.id) + v_cd: int64 = self._cdefine_int_of(node) if self.Gen.TypeGenCDef.is_cdefine_found() == 0: return 0 if v_cd < 0: return 0 w_cd: int = self.Gen.AssignGen.define_min_width(v_cd)