Files
Viper_RegressionTesting/IntWidthTest/App/main.vp
T
2026-10-17 21:57:03 +08:00

132 lines
6.4 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import testcheck
# 浮现点:整型“最小宽度”回绕 + i64 移位不收敛(同一族 bug 的四个面)。
# 现场来源:
# ① Gargantua: define V3_POOL_BYTES = V3_POOL_SIZE * 24 + 512(8192*24 被按 i16 算成 0 → 得 512)
# ② vpsdk/window.vp: define WINBUF_MAX_BYTES = 1024 * 1024 * 4(按 i16 → 0;随后内核 memcpy 越界)
# ③ ViperC 自身: `while t != 0: t = t >> 1`(t 为 int64)在生成代码里不收敛 → 编译期死循环
# 注:ViperC 由 TPC 引导,本用例同时用来照 TPC 侧的同源实现。
define V3_POOL_SIZE = 8192
define V3_POOL_BYTES = V3_POOL_SIZE * 24 + 512
def test_static_defines():
"""静态 define 算式必须按**结果值**拓宽,不能按最小宽度回绕。"""
testcheck.section("Test 1: define 算式(静态求值)不按最小宽度回绕")
testcheck.check(V3_POOL_BYTES == 197120, "V3_POOL_SIZE * 24 + 512 == 197120",
"按 i16 回绕会得到 512(8192*24 = 196608 = 0x30000,低 16 位正好为 0)")
def test_runtime_const_expr():
"""运行期纯常量算式同样不能按最小宽度回绕。"""
testcheck.section("Test 2: 运行期纯常量算式不按最小宽度回绕")
v: int = 1024 * 1024 * 4
testcheck.check(v == 4194304, "1024 * 1024 * 4 == 4194304", "按 i16 回绕会得到 0")
def test_i64_shift_value():
"""i64 的 >> 必须是真 64 位移位(移位计数需与左操作数同宽)。"""
testcheck.section("Test 3: i64 >> 的值正确")
x: int64 = 0x30000
y: int64 = x >> 1
testcheck.check(y == 0x18000, "i64 0x30000 >> 1 == 0x18000", "窄移位会保留高位 → 值错")
def test_i64_shift_loop_converges():
"""核心浮现点:i64 右移循环必须收敛。
若 `>>` 的计数没有与左操作数同宽(按最小宽度 i32 发射),只会移低 32 位,
i64 高位永不清零,而 `x != 0` 是全宽比较 → 永不收敛(ViperC 曾在编译期死在这里)。
这里加 200 次上限:出 bug 时以“次数不对”报错,而不是把测试挂死。
"""
testcheck.section("Test 4: i64 右移循环收敛(0x30000 需 18 次归零)")
x: int64 = 0x30000
n: int = 0
while x != 0:
x = x >> 1
n += 1
if n > 200: break
testcheck.check(n == 18, "0x30000 右移 18 次归零", "窄移位则永不归零(次数 > 32 或触发 200 次上限)")
def test_i64_negative_shift():
"""负数形态:钉死 ViperC 编译期死循环的真正机理。
`-196608 >> 1` 是**算术**右移(= -98304);负数直接右移永远停在负数、`!= 0` 永不成立
——这正是当时 ViperC 里 `while t != 0: t = t >> 1`(t 为负)死循环的形态。
这里用 200 次上限把它“有界复现”:m 应为 201(说明是算术右移,永不归零);
若 m 明显更小(例如 ~49)说明按**逻辑**右移处理了负数(把负数当无符号)。
"""
testcheck.section("Test 5: 负数 i64 的算术右移(死循环原形态,有界复现)")
x: int64 = -196608
y: int64 = x >> 1
testcheck.check(y == -98304, "-196608 >> 1 == -98304(算术右移)", "按逻辑右移会得到很大的正数")
w: int64 = -196608
m: int = 0
while w != 0:
w = w >> 1
m += 1
if m > 200: break
testcheck.check(m == 201, "负数直接右移永不归零(触发 200 次上限)", "m 偏小说明被按逻辑右移处理,语义不对")
# 定宽实现必须先取反再数位(本次修复采用),验证它对负数也能收敛
z: int64 = x ^ int64(-1) # ~(-196608) = 196607
n: int = 0
while z != 0:
z = z >> 1
n += 1
if n > 200: break
testcheck.check(n == 18, "~(-196608) = 196607 右移 18 次归零", "先取反再数位应能收敛(ViperC 修复后的写法)")
def test_negative_source():
"""判别:负数来自**负字面量**(一元负号)还是**运算结果** —— 用来定位 TPC 把谁登记成无符号。
TPC 的 `>>` 符号性取自 `var_signedness[name]`(按变量名登记,登记源是某类型串)。
若下面第 1 条 FAIL、第 2 条 PASS ⇒ 是“负字面量”被判成无符号(字面量一元负号路径);
若两条都 FAIL ⇒ 是对“负值”一律按无符号处理。
"""
testcheck.section("Test 6: 负数的来源(字面量 vs 运算)")
b: int64 = -196608 # 一元负号作用于字面量
cb: int64 = b >> 1
# 直接断言裸值:赋值/物化阶段就必须是 -196608(曾被 zext 成 4294770688 = 0x00000000FFFD0000)。
testcheck.check(b == -196608, "负字面量赋值本身正确(b == -196608)",
"FAIL ⇒ 赋值/物化阶段就把 -196608 弄错了")
testcheck.check(cb == -98304, "负**字面量**变量右移仍为算术右移", "FAIL ⇒ 负字面量被登记成无符号")
c: int64 = 0 - 196608 # 由运算产生的负数
cc: int64 = c >> 1
testcheck.check(cc == -98304, "由**运算**得到负数的变量右移为算术右移", "FAIL ⇒ 对负值一律按无符号处理")
def test_explicit_cast_widths():
"""显式强转:加宽保符号(sext)、窄化截断(trunc)——不受“隐式窄化禁止”约束。
现场:TPC 编译 ViperC 时 `LONG(BUF_B)`(sizet/u64 → int32,Windows LLP64 下 LONG 为 32 位)
被判成“隐式窄化禁止”而 FailFastError(TypeGenResolve.vp:1065)。显式转换必须允许 trunc;
加宽必须 sext,否则 `int64(int32(-1))` 会变成 4294967295。
"""
testcheck.section("Test 7: 显式强转的加宽/窄化")
n: sizet = 65536
n32: int32 = int32(n)
testcheck.check(n32 == 65536, "int32(sizet 65536) == 65536(显式窄化=截断)",
"编译失败/FAIL ⇒ 显式窄化被当成隐式窄化拒绝(FailFastError)")
neg: int32 = -1
wide: int64 = int64(neg)
testcheck.check(wide == -1, "int64(int32 -1) == -1(显式加宽保符号)",
"FAIL ⇒ 显式加宽用了 zext,-1 变 4294967295")
def main() -> int:
testcheck.begin("IntWidthTest: 整型常量/移位的最小宽度回绕与 i64 移位收敛")
test_static_defines()
test_runtime_const_expr()
test_i64_shift_value()
test_i64_shift_loop_converges()
test_i64_negative_shift()
test_negative_source()
test_explicit_cast_widths()
return testcheck.end()