Skip to content

[Bug] PTODSL-vmi,vcvt IntNarrow {saturate="SAT"} 饱和取值写死 0xFF,未按 contract 方向 clamp 到 dst ±max/umin;signed dst 还对 in-range 负值误判越界 #1389

Closed

Description

@chenben09

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

10883a8

Host platform

Linux (aarch64)

Target Ascend arch (if relevant)

a5

PTOAS build level (if relevant)

None

Activity

  1. self-assigned this
    on Sep 1, 2026
  2. Zhendong404 commented on Sep 2, 2026

    @Zhendong404
    Collaborator

    补充结论(按 VMI/DSL 类型契约核对):

    当前 VMI 语义中,iN 是 signless integer,vcvt 对 signless 整数采用 unsigned 数值语义;uiN 是显式 unsigned,siN 才是 signed。也就是说:

    • i16 -> i8, saturate="SAT" 的饱和范围是 [0, 255];
    • 需要 signed 数值转换时,应使用显式的 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 范围定义。

    本次不修改测试框架。建议后续将测试按语义拆分:

    1. iN/uiN 用非负输入,golden 按 unsigned 范围计算;
    2. signed SAT 用 siN -> siN,并单独确认目标后端是否提供对应 dtype pair;
    3. 如果目标确实要求 iN 表示 signed,则需要先修改 VMI 类型契约和 DSL/IR verifier,而不能只调整 lowering 或 golden。
  3. Zhendong404 commented on Sep 2, 2026

    @Zhendong404
    Collaborator
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

QAIssues from the QA teambugSomething isn't workingvmi

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions