fix(viperc): 运行期纯常量整型算式按精确值折叠并按值定宽,禁止最小宽度回绕

- 现场:`1024 * 1024 * 4` 在表达式侧按最小宽度(i16)运算,1024×1024 先回绕成 0 ⇒ 常量变 0(WINBUF_MAX_BYTES=0 ⇒ 窗口缓冲只剩几字节 ⇒ 内核 memcpy 240KB 越界读 → 三重故障)

- 在 translate_binop 取到操作数类型后加入纯常量折叠:+ - * | & ^ << >> 两侧都是编译期整型常量时按精确值求结果,并按“能精确容纳该值的最小合法宽度(下限取操作数较宽者)”定宽、向上取 8/16/32/64;只有装不下才加宽(与 61f23d9 的静态求值器同口径)

- 与 61f23d9 合起来:静态 define 求值与运行期常量算式都不再按最小宽度回绕
This commit is contained in:
TermiNexus committed 2026-10-14 19:39:11 +08:00
1 parent 61f23d99a1
commit d09b79995d
1 file changed
+36
+36
View File
@@ -1332,6 +1332,42 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase):
lhs_fbits: int = self.get_llvm_float_bits(lhs.Ty)
rhs_fbits: int = self.get_llvm_float_bits(rhs.Ty)
# 纯常量整型算式(两侧都是编译期整型常量):按**精确值**折叠并按值定宽,
# 禁止按操作数的最小宽度回绕(现场:`1024 * 1024 * 4` 按 i16 算成 0 ⇒
# WINBUF_MAX_BYTES=0 ⇒ 窗口缓冲只剩几字节 ⇒ 内核 memcpy 240KB 越界读/三重故障)。
if lhs_bits > 0 and rhs_bits > 0 and lhs.IsConst == 1 and rhs.IsConst == 1:
cf_ok: int = 1
cf_v: int64 = 0
if op == ast.OpKind.Add: cf_v = lhs.IntVal + rhs.IntVal
elif op == ast.OpKind.Sub: cf_v = lhs.IntVal - rhs.IntVal
elif op == ast.OpKind.Mult: cf_v = lhs.IntVal * rhs.IntVal
elif op == ast.OpKind.BitOr: cf_v = lhs.IntVal | rhs.IntVal
elif op == ast.OpKind.BitAnd: cf_v = lhs.IntVal & rhs.IntVal
elif op == ast.OpKind.BitXor: cf_v = lhs.IntVal ^ rhs.IntVal
elif op == ast.OpKind.LShift or op == ast.OpKind.RShift:
if rhs.IntVal >= 0 and rhs.IntVal < 64:
if op == ast.OpKind.LShift: cf_v = lhs.IntVal << rhs.IntVal
else: cf_v = lhs.IntVal >> rhs.IntVal
else: cf_ok = 0
else: cf_ok = 0
if cf_ok != 0:
# 定宽:下限取操作数较宽者,只有精确值装不下才加宽(避免把 `A + 1` 这类
# 常量算式整体抬成 i64,引出新的“隐式窄化”报错)。
cf_w: int = lhs_bits if lhs_bits > rhs_bits else rhs_bits
if cf_v != 0:
t_cf: int64 = cf_v
if cf_v < 0: t_cf = cf_v ^ int64(-1)
vw_cf: int = 1 # 符号位
while t_cf != 0:
vw_cf += 1
t_cf = t_cf >> 1
if vw_cf > cf_w: cf_w = vw_cf
if cf_w <= 8: cf_w = 8
elif cf_w <= 16: cf_w = 16
elif cf_w <= 32: cf_w = 32
else: cf_w = 64
return mlirlite.const_int(pool, cf_w, cf_v)
# Float operation: use float instructions when either operand is float (must precede pointer arithmetic, since float has 0 int bits and would be mistaken for a pointer).
if lhs_fbits != 0 or rhs_fbits != 0:
# Determine the target float type (use the larger bit width)