Skip to content

[Bug] [阻塞] PTODSL: variable reassignment inside pto.if_ is not carried out correctly and may cause dominance errors #1073

Description

@W4termy

Component

Python bindings (python/)

Description

PTODSL 中,如果一个变量在 pto.if_ 的 then/else region 内被重新赋值,并且这个变量在 pto.if_ 之后继续使用,目前看起来没有被正确 lower 成 scf.if 的 result/yield。

这会导致两类问题:

  1. 简单赋值可能被错误地当成无条件赋值,scf.if 变成空 region,语义错误。
  2. 如果赋值 RHS 是在 pto.if_ region 内新产生的 SSA value,则会在后续使用时报 MLIR dominance error。

这和 #973 类似,都是 PTODSL AST rewrite / SSA carry 对 Python rebinding 的处理问题;但这里触发点是 pto.if_,不是 for loop 里的 list subscript self assignment。

Reproduction (minimal)

Case 1: assignment inside `pto.if_` is silently treated as if it were unconditional


from ptodsl import pto

@pto.jit(name="repro_if_reassign_wrong_semantics", target="a5")
def kernel(n: pto.i32) -> None:
    mask = pto.pset_b32("PAT_ALL")

    x = pto.const(0, dtype=pto.i32)
    with pto.if_((n > 0)) as br, br.then_:
        x = n

    # Expected: vdup uses (n if n > 0 else 0)
    # Actual: vdup uses n unconditionally
    v = pto.vdup(x, mask)
    return

print(kernel.compile().mlir_text())

Actual generated MLIR excerpt:
%1 = arith.cmpi sgt, %arg0, %c0_i32_0 : i32
scf.if %1 {
}
%2 = pto.vdup %arg0, %0 : i32, !pto.mask<b32> -> !pto.vreg<64xi32>

The scf.if is empty, and %arg0 is used unconditionally after the if.

Case 2: assignment to a value created inside pto.if_ causes MLIR dominance failure

from ptodsl import pto

@pto.jit(name="repro_if_reassign_dominance", target="a5")
def kernel(n: pto.i32) -> None:
    mask = pto.pset_b32("PAT_ALL")

    x = pto.const(0, dtype=pto.i32)
    with pto.if_((n > 0)) as br, br.then_:
        x = n + 1

    # Expected: vdup uses if-result (n + 1 if n > 0 else 0)
    # Actual: value from child region is used outside, causing dominance error
    v = pto.vdup(x, mask)
    return

print(kernel.compile().mlir_text())

Expected behavior

Variables reassigned inside pto.if_ should be modeled as values yielded from the scf.if region, similar to:
%new_x = scf.if %cond -> (i32) {
%then_x = arith.addi %arg0, %c1_i32 : i32
scf.yield %then_x : i32
} else {
scf.yield %old_x : i32
}

%v = pto.vdup %new_x, %mask : i32, !pto.mask -> !pto.vreg<64xi32>

For pto.if_ without an explicit else branch, the else value should preserve the previous value of the variable.

Actual behavior / error logs

ptoas.mlir._mlir_libs._site_initialize.<locals>.MLIRError: Verification failed:
error: unknown: operand #0 does not dominate this use
 note: unknown: see current operation: %4 = "pto.vdup"(%6, %0) : (i32, !pto.mask<b32>) -> !pto.vreg<64xi32>
 note: unknown: operand defined here (op in a child region)

Git commit

8cd7219

Host platform

None

Target Ascend arch (if relevant)

a5

PTOAS build level (if relevant)

None

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions