diff --git a/App/lib/core/Gen/AssignGenMixin.vp b/App/lib/core/Gen/AssignGenMixin.vp index 8379e88..05ed170 100644 --- a/App/lib/core/Gen/AssignGenMixin.vp +++ b/App/lib/core/Gen/AssignGenMixin.vp @@ -189,17 +189,27 @@ novirtual class AssignGenMixin: return 0 def _normalize_cdefine_bits(self, value: int64, bits: int) -> int64: - """把值按位宽**截断**后再重解释为该位宽的有符号表示(与 ExprGenCdef._cdefine_bits_value 同口径)。 + """把值按位宽处理:**只有在当前位宽的两种解释下都装不下时才截断**,否则原样保留 + (与 ExprGenCdef._cdefine_bits_value 同口径)。 - 「左侧只会看到截断了的数据」:超宽的值先按 bits 取低位(如 WORD(0x80000000) → 0), - 不是直接把原值搬过来、也不是只对"刚好越界一点"的值做重解释。 - 实现用左移后算术右移,而不是 `value & 0xFFFFFFFF` 这类大掩码字面量: - 掩码字面量(如 4294967295)超出 int32 范围,其加宽方向在 TPC/VPC 上可能判成 sext, - 会得到 0xFFFFFFFFFFFFFFFF 而不是 0xFFFFFFFF,导致截断失效。 + 「左侧只会看到截断了的数据」:超宽的值先按 bits 取低位(如 WORD(0x80000000) → 0)。 + 但**不**把"无符号可容、有符号装不下"的正值重解释成负数:旧实现无条件 + `(value << 56) >> 56`,8 位下的 160 变成 -96,正值静默变负,常量算式随之算错 + (现场:Gargantua `GW * GH * 4` = 57600 被折成 -34560)。 + 实现仍避开大掩码字面量(见下)。 """ - if bits == 8: return (value << 56) >> 56 - if bits == 16: return (value << 48) >> 48 - if bits == 32: return (value << 32) >> 32 + if bits == 8: + if value >= -128 and value <= 127: return value + if value > 127 and (value >> 8) == 0: return value + return (value << 56) >> 56 + if bits == 16: + if value >= -32768 and value <= 32767: return value + if value > 32767 and (value >> 16) == 0: return value + return (value << 48) >> 48 + if bits == 32: + if value >= -2147483647 - 1 and value <= 2147483647: return value + if value > 2147483647 and (value >> 32) == 0: return value + return (value << 32) >> 32 return value def cdefine_decl_bits(self, pool: memhub.MemBuddy*, annot: ast.AST*, value_node: ast.AST*) -> int: diff --git a/App/lib/core/Gen/Expr/ExprGenCdef.vp b/App/lib/core/Gen/Expr/ExprGenCdef.vp index 5dbc2f1..578172a 100644 --- a/App/lib/core/Gen/Expr/ExprGenCdef.vp +++ b/App/lib/core/Gen/Expr/ExprGenCdef.vp @@ -842,17 +842,27 @@ novirtual class ExprGenCdef(ExprGenBase.ExprGenBase): # ============================================================ # cdefine_use_width_value - materialize CDefine constants at the use-site width (TPC-aligned) def _cdefine_bits_value(self, value: int64, bits: int) -> int64: - """把值按位宽**截断**后再重解释为该位宽的有符号表示(与 AssignGenMixin._normalize_cdefine_bits 同口径)。 + """把值按位宽处理:**只有在当前位宽的两种解释下都装不下时才截断**,否则原样保留。 - 「左侧只会看到截断了的数据」:超宽的值先按 bits 取低位(WORD(0x80000000) → 0), - 而不是只对"刚好越界一点"的值做重解释。 - 实现用左移后算术右移,而不是 `value & 0xFFFFFFFF` 这类大掩码字面量: - 掩码字面量(如 4294967295)超出 int32 范围,其加宽方向在 TPC/VPC 上可能判成 sext, - 会得到 0xFFFFFFFFFFFFFFFF 而不是 0xFFFFFFFF,导致截断失效。 + 「左侧只会看到截断了的数据」:超宽的值先按 bits 取低位(如 WORD(0x80000000) → 0)。 + 但不该把"无符号可容、有符号装不下"的**正值**重解释成负数:旧实现无条件 + `(value << 56) >> 56`,8 位下的 160 被读成 -96,正值静默变负 —— 现场 + Gargantua `_start` 的 `string.memset(fb, 0, GW * GH * 4)`(GW=160, GH=90) + 被折成 -34560,作为长度写穿映射区 → #PF。位型不变(const_int 本就按位宽截断), + 只是不再翻转可容正值的语义。实现仍避开大掩码字面量(见下)。 """ - if bits == 8: return (value << 56) >> 56 - if bits == 16: return (value << 48) >> 48 - if bits == 32: return (value << 32) >> 32 + if bits == 8: + if value >= -128 and value <= 127: return value + if value > 127 and (value >> 8) == 0: return value + return (value << 56) >> 56 + if bits == 16: + if value >= -32768 and value <= 32767: return value + if value > 32767 and (value >> 16) == 0: return value + return (value << 48) >> 48 + if bits == 32: + if value >= -2147483647 - 1 and value <= 2147483647: return value + if value > 2147483647 and (value >> 32) == 0: return value + return (value << 32) >> 32 return value def cdefine_use_width_value(self, pool: memhub.MemBuddy*, node: ast.AST*, name: str, value: int64, target_ty: mlirlite.LLVMType*, use_ctx: str = None) -> mlirlite.Value*: