Repository navigation
[Bug] PTODSL-vmi,vcvt IntNarrow {saturate="SAT"} 饱和取值写死 0xFF,未按 contract 方向 clamp 到 dst ±max/umin;signed dst 还对 in-range 负值误判越界 #1389
Description
Component
PTO Dialect / ODS (include/PTO/IR)
Description
在 A5 平台测试 pto.vmi.vcvt 的 IntNarrow(int→int, |dst|<|src|)+ saturate="SAT" 场景时,VMI→VPTO lowering 对需要饱和的 lane 统一写固定 0xFF(全 1)标记。0xFF 按 dst 符号性 reinterpret(signed dst→-1,unsigned dst→255=umax),表现为三类缺陷,涉及 9 个 dtype 对:
缺陷①(signed dst 越界写 0xFF(-1) 而非 ±max):正溢出应 clamp 到 +dst.max、负下溢应 clamp 到 dst.min,实际都写 -1。涉及 6 个 dtype 对——s→s 的 i16→i8、i32→i8、i32→i16(正溢出+负下溢均错),以及 u→s 的 ui16→i8、ui32→i8、ui32→i16(仅正溢出错,负下溢因 unsigned 源取不到负值而不触发)。
缺陷②(signed dst in-range 负值误判越界、写 0xFF):源值为 dst 范围内的负值(如 -39 ∈ -128,127)本该保值,实际输出 -1——越界判定对 signed dst 用了 [0, dst.max] 而非 [dst.min, dst.max]。涉及 3 个 dtype 对:s→s 的 i16→i8、i32→i8、i32→i16(需 signed 源产生负值 + signed dst 含负区间)。
缺陷③(unsigned dst 负下溢写 0xFF(umax) 而非 umin=0):负值应 clamp 到 unsigned dst 的 min=0,实际 clamp 到 max=255(0xFF 恰好=umax 的巧合,故 s→u 正溢出误判 PASS)。涉及 3 个 dtype 对:s→u 的 i16→ui8、i32→ui8、i32→ui16(仅负下溢错,正溢出巧合 PASS)。
saturate="NOSAT" 不受影响(位截断正确,102/102 PASS);unsigned→unsigned SAT 全 PASS。golden(np.clip/torch.clamp)与按位比对(np.array_equal)均正确,缺陷仅在 DUT lowering。
Reproduction (minimal)
关键kernel函数
@jit_kernel(name, params)
def kernel(src_ptr: pto.ptr(src_ptype, "gm"), out_ptr: pto.ptr(dst_ptype, "gm")):
src_ub = pto.castptr(pto.i64(0), pto.ptr(src_ptype, "ub"))
out_ub = pto.castptr(pto.i64(src_nbytes), pto.ptr(dst_ptype, "ub"))
pto.mte_gm_ub(src_ptr, src_ub, 0, src_nbytes, nburst=(1, 0, 0))
pto.set_flag("MTE2", "V", event_id=0)
pto.wait_flag("MTE2", "V", event_id=0)
source = pto.vmi.vload(src_ub, pto.const(0, dtype=pto.index), size=vl)
result = pto.vmi.vcvt(source, to_dtype, saturate="SAT") # IntNarrow, src_bits>dst_bits
pto.vmi.vstore(result, out_ub, pto.const(0, dtype=pto.index))
pto.set_flag("V", "MTE3", event_id=0)
pto.wait_flag("V", "MTE3", event_id=0)
pto.mte_ub_gm(out_ub, out_ptr, dst_nbytes, nburst=(1, 0, 0))Expected behavior
SAT: overflow(>dst.max)→+dst.max;underflow(<dst.min)→dst.min;in-range→保值
NOSAT: 位截断(wrap)
Actual behavior / error logs
数值比对按位不一致(cann_bench(int) 按位不一致 N/N),DUT 对越界/负值 lane 输出恒定 0xFF(与 src 无关)。共 9 个 dtype 对、54 例 SAT FAIL。各 dtype 对的上溢/下溢错误场景代表用例
(s→s(signed dst,上溢+下溢均错,缺陷①+②):
- i16→i8 上溢 i16_i8_vl256_u_a256_n_r3over_sSAT(A=-1 G=127);下溢 i16_i8_vl256_u_a256_n_r1under_sSAT(A=-1 G=-128)
- i32→i8 上溢 i32_i8_vl256_u_a256_n_r3over_sSAT(A=-1 G=127);下溢 i32_i8_vl256_u_a256_n_r1under_sSAT(A=-1 G=-128)
- i32→i16 上溢 i32_i16_vl256_u_a256_n_r3over_sSAT(A=-1 G=32767);下溢 i32_i16_vl256_u_a256_n_r1under_sSAT(A=-1 G=-32768)
s→u(unsigned dst,仅下溢错,缺陷③):
- i16→ui8 下溢 i16_ui8_vl256_u_a256_n_r1under_sSAT(A=255 G=0);上溢 i16_ui8_vl256_u_a256_n_r3over_sSAT PASS(0xFF=umax 巧合)
- i32→ui8 下溢 i32_ui8_vl256_u_a256_n_r1under_sSAT(A=255 G=0);上溢 i32_ui8_vl256_u_a256_n_r3over_sSAT PASS
- i32→ui16 下溢 i32_ui16_vl256_u_a256_n_r1under_sSAT(A=65535 G=0);上溢 i32_ui16_vl256_u_a256_n_r3over_sSAT PASS
u→s(signed dst,仅上溢错,缺陷①):
- ui16→i8 上溢 ui16_i8_vl256_u_a256_n_r3over_sSAT(A=-1 G=127);下溢 N/A(unsigned 源无负值)
- ui32→i8 上溢 ui32_i8_vl256_u_a256_n_r3over_sSAT(A=-1 G=127);下溢 N/A
- ui32→i16 上溢 ui32_i16_vl256_u_a256_n_r3over_sSAT(A=-1 G=32767);下溢 N/A
未受影响(反证 golden 正确):NOSAT 全 102/102 PASS;u→u SAT 21/21 PASS(ui16→ui8、ui32→ui8、ui32→ui16);s→u 正溢出 9/9 PASS。
Git commit
Host platform
Linux (aarch64)
Target Ascend arch (if relevant)
a5
PTOAS build level (if relevant)
None
Activity
Zhendong404 commentedon Sep 2, 2026
补充结论(按 VMI/DSL 类型契约核对):
当前 VMI 语义中,
iN是 signless integer,vcvt对 signless 整数采用 unsigned 数值语义;uiN是显式 unsigned,siN才是 signed。也就是说:i16 -> i8, saturate="SAT"的饱和范围是[0, 255];si16/si8(前提是该 dtype pair 在目标后端受支持);i16不是si16的别名,不能仅因为 host 侧用numpy/torch int16承载负数,就把它解释为 signed VMI 数值。因此,当前 issue 中使用
i16/i8、但 golden 按 signed[-128,127]计算的场景,存在测试输入类型与 VMI 语义不一致的问题。0xFF的现象正是 signless→unsigned 后执行 unsigned SAT 的结果;这不代表 VMI 规范下的i16->i8应执行 signed clamp。我已同步澄清文档:
ptodsl/docs/user_guide/14-vmi-virtual-instruction-set.md:说明iN的 unsigned 语义适用于 int widening 和 narrowing,并明确iN不等同于siN;docs/isa/vmi-isa/06-convert.md:补充 signed/unsigned/signless 的类型规则和 SAT 范围定义。本次不修改测试框架。建议后续将测试按语义拆分:
iN/uiN用非负输入,golden 按 unsigned 范围计算;siN -> siN,并单独确认目标后端是否提供对应 dtype pair;iN表示 signed,则需要先修改 VMI 类型契约和 DSL/IR verifier,而不能只调整 lowering 或 golden。Zhendong404 commentedon Sep 2, 2026
Gitcode PR: https://gitcode.com/cann/pto-as/pull/3