From 55a6856c4ef7862187b99d499cd444a71bdc267f Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Wed, 14 Oct 2026 20:18:26 +0800 Subject: [PATCH] =?UTF-8?q?fix(tpc):=20`>>`=20=E7=AC=A6=E5=8F=B7=E6=80=A7?= =?UTF-8?q?=E5=8F=AA=E6=8C=89=E5=B7=A6=E6=93=8D=E4=BD=9C=E6=95=B0=E5=88=A4?= =?UTF-8?q?=E5=AE=9A=EF=BC=8C=E5=8E=BB=E6=8E=89=E2=80=9C=E6=AE=8B=E7=95=99?= =?UTF-8?q?=E5=8F=98=E9=87=8F=E5=90=8D=E2=80=9D=E8=AF=AF=E5=88=A4=EF=BC=88?= =?UTF-8?q?=E8=B4=9F=E6=95=B0=E5=8F=B3=E7=A7=BB=E5=8F=91=E6=88=90=20lshr?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 现场:`b: int64 = -196608; b >> 1` 发成 lshr ⇒ 负数变大正数;而同样注解的 `c: int64 = 0 - 196608; c >> 1` 却正确 ⇒ 与 RHS/位置相关(IntWidthTest Test 5/6) - 根因:emit_binary_op 在 i32/i64 分支又用 self._last_var_name 重判符号性,而它只是“最近见过的变量名”,可能是上一条表达式残留的别的(无符号)变量 ⇒ 误判无符号 - 改动:① ExprGen.emit_binary_op 删除 i32/i64 的 _last_var_name 分支(符号性只信调用方;i8/i16 仍按宽度定无符号);② HandlesExprOps 的 `>>` 改用 _check_node_unsigned(Node.left),覆盖 Name 之外的形态 - 验收:Test/IntWidthTest(Test 5/6),目标 TPC 侧 9/9 PASS --- lib/core/Handles/HandlesExprOps.py | 8 +++++--- lib/core/LLVMCG/ExprGen.py | 12 ++++++------ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/lib/core/Handles/HandlesExprOps.py b/lib/core/Handles/HandlesExprOps.py index 5a090c9..476a7d4 100644 --- a/lib/core/Handles/HandlesExprOps.py +++ b/lib/core/Handles/HandlesExprOps.py @@ -140,9 +140,11 @@ class ExprOpsHandle(BaseHandle): RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_deref_right") elif RightVal.type.width > LeftVal.type.width: LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_left_deref") - if Op in ('>>', 'RShift') and isinstance(Node.left, ast.Name): - vname: str = Node.left.id - if vname in Gen.var_signedness and Gen.var_signedness[vname]: + # `>>` 的符号性按**左操作数**判定:Name 之外的形态(字段/下标/表达式)也要覆盖。 + # 注意不要退回 emit_binary_op 里那个“残留变量名”判据(已移除,见 ExprGen.emit_binary_op): + # b: int64 = -196608; b >> 1 曾是误判成 lshr 的现场(IntWidthTest Test 5/6)。 + if Op in ('>>', 'RShift'): + if Gen._check_node_unsigned(Node.left): is_unsigned = True # 双指针算术 fail-fast 已**下沉到单一收敛点** `Gen.emit_binary_op` # (LLVMCG/ExprGen.py):BinOp 与 AugAssign(+=、-=、*= …)都经该函数, diff --git a/lib/core/LLVMCG/ExprGen.py b/lib/core/LLVMCG/ExprGen.py index 0adf7c7..203f8a6 100644 --- a/lib/core/LLVMCG/ExprGen.py +++ b/lib/core/LLVMCG/ExprGen.py @@ -179,12 +179,12 @@ class ExprGenMixin: is_unsigned = True elif left.type.width == 16: is_unsigned = True - elif left.type.width == 32: - if self._last_var_name: - is_unsigned = self._is_var_unsigned(self._last_var_name) - elif left.type.width == 64: - if self._last_var_name: - is_unsigned = self._is_var_unsigned(self._last_var_name) + # i32/i64 的符号性**只由调用方按左操作数判定**(调用方拿得到 Node.left, + # 见 HandlesExprOps / HandlesAugAssign)。此前这里又用 self._last_var_name + # 判一次,而它只是“最近见过的变量名”,可能是**上一条表达式残留的别的变量**: + # b: int64 = -196608 + # b >> 1 # 若残留名恰好是某个无符号变量(t.CSizeT 等) ⇒ 误判无符号 ⇒ lshr + # 结果:负数右移变大正数(IntWidthTest Test 5/6 的 FAIL 即此)。 shift_ops: dict[str, Any] = { '>>': self.builder.lshr if is_unsigned else self.builder.ashr, 'RShift': self.builder.lshr if is_unsigned else self.builder.ashr,