fix(tpc): 负数常量与负值整型加宽改为保符号,sext 与常量折叠,不再零扩展

根因:多处手写 zext 做整型加宽,把有符号为负的常量当无符号处理。涉及 HandlesAnnAssign 局部标量初始化两处、HandlesExprCall 的 typedef 与 builtins 强转两处。

一元负号对常量无条件发运行期 neg,常量 -1 变成 neg i32 指令后再被零扩展成 4294967295。

_eval_global_const 用无符号读回值取负,-196608 被物化成 4294770688 即 0x00000000FFFD0000。

现场:b 为 int64 等于 -196608 后,b 右移 1 呈逻辑右移假象,负数右移循环不收敛,见 IntWidthTest Test 5 与 Test 6。

改法:统一收敛到 _coerce_value,加宽用 sext,窄化按其规则 fail-fast;一元负号对常量直接折叠为有符号常量;_eval_global_const 先按位宽还原带符号真值。

另修右移符号性:去掉 emit_binary_op 里按 self._last_var_name 的残留变量名重判,调用方改按 _check_node_unsigned 判定。

验收:Test/IntWidthTest 10 项全 PASS,此前 TPC 侧 5 项通过 2 项失败。
This commit is contained in:
TermiNexus committed 2026-10-14 20:49:35 +08:00
1 parent 55a6856c4e
commit aaf9330b3b
3 files changed
+43 -22

No files matched your search

+9
View File
@@ -287,6 +287,15 @@ class ExprOpsHandle(BaseHandle):
and not isinstance(Node.operand.value, bool):
RequireIntLiteralStorable(Gen, self.Trans, Node, -Node.operand.value)
if isinstance(OperandVal.type, ir.IntType):
# 常量直接折叠成常量(保持有符号位型):此前无条件发运行期 neg,常量 `-1`
# 变成一条 `neg i32` 指令,随后加宽时被零扩展 ⇒ 4294967295
# (现场:`int64(-1)` ⇒ `x ^ int64(-1)` 变号、循环不收敛;
# IntWidthTest Test 5 第三条)。
if isinstance(OperandVal, ir.Constant) and isinstance(getattr(OperandVal, 'constant', None), int):
_uw: int = OperandVal.type.width
_uv: int = int(OperandVal.constant) & ((1 << _uw) - 1)
_sv: int = _uv - (1 << _uw) if _uv >= (1 << (_uw - 1)) else _uv
return ir.Constant(OperandVal.type, -_sv)
return Gen.builder.neg(OperandVal, name="neg_result")
elif isinstance(OperandVal.type, (ir.FloatType, ir.DoubleType)):
return Gen.builder.fneg(OperandVal, name="fneg_result")