Skip to content

ConstProp crashes with DeletedSSAValue on triple-nested for-loops over IList[IList[...]] #646

@yzcj105

Description

@yzcj105

Description

The constant propagation pass crashes with InterpreterError: SSAValue <DeletedSSAValue[State]...> not found when processing a kernel that contains triple-nested for-loops iterating over IList[IList[MeasurementResult, Any], Any].

The same logic expressed without loops (manually unrolled) compiles and runs correctly.

Minimal Reproduction

The reproduction requires bloqade-lanes (branch rafaelha/mvp_decoding) because the bug is triggered during compile_to_physical_stim_program, which calls the kirin aggressive-unroll → hint-const → constprop pipeline.

from bloqade.gemini import logical as gemini_logical
from bloqade import qubit, squin, annotate, types
from bloqade.lanes.logical_mvp import (
    compile_to_physical_stim_program,
    kernel,
    set_observable,
)
from kirin.dialects import ilist
from typing import Any


# ── This kernel triggers the bug ──────────────────────────────
@kernel
def set_detector_loopy(
    meas: ilist.IList[ilist.IList[types.MeasurementResult, Any], Any],
):
    h = [[0, 1, 2, 3], [1, 2, 4, 5], [2, 3, 4, 6]]
    num_meas = len(meas)
    for i in range(len(h)):
        stab = h[i]
        res = []
        for j in range(4):
            for k in range(num_meas):
                m = meas[k]
                res = res + [m[stab[j]]]
        annotate.set_detector(res, coordinates=[0, i])


# ── This equivalent kernel works fine ─────────────────────────
@kernel
def set_detector_unrolled(meas: ilist.IList[types.MeasurementResult, Any]):
    annotate.set_detector([meas[0], meas[1], meas[2], meas[3]], coordinates=[0, 0])
    annotate.set_detector([meas[1], meas[2], meas[4], meas[5]], coordinates=[0, 1])
    annotate.set_detector([meas[2], meas[3], meas[4], meas[6]], coordinates=[0, 2])


@kernel
def circuit():
    reg = qubit.qalloc(2)
    squin.h(reg[0])
    squin.cx(reg[0], reg[1])
    measurements = gemini_logical.terminal_measure(reg)
    set_detector_loopy(measurements)          # ← crashes
    # Workaround: use unrolled version per-qubit instead
    # set_detector_unrolled(measurements[0])  # ← works
    # set_detector_unrolled(measurements[1])  # ← works
    set_observable(measurements[0], 0)
    set_observable(measurements[1], 1)

program = compile_to_physical_stim_program(circuit)  # raises InterpreterError

Stack Trace

File "kirin/passes/hint_const.py", line 18, in unsafe_run
    frame, _ = constprop.run(mt)
File "kirin/analysis/forward.py", line 41, in run
    return self.call(method, self.method_self(method), *args, **kwargs)
  ...
File "kirin/dialects/cf/constprop.py", line 40, in conditional_branch
    stmt.then_successor, *frame.get_values(stmt.then_arguments)
File "kirin/interp/frame.py", line 121, in get
    raise InterpreterError(f"SSAValue {key} not found")
kirin.interp.exceptions.InterpreterError: SSAValue <DeletedSSAValue[State] value: <ResultValue[State] stmt: load, uses: 0>, uses: 6> not found

The full call chain is:
compile_to_physical_stim_programsquin_to_stimSquinToStimPassFlatten.fixpointAggressiveUnrollHintConstConstProp.run → crash in cf/constprop.py:conditional_branch

Versions Tested

Version Result
kirin-toolchain 0.22.6 (PyPI) FAIL
kirin-toolchain 0.22.9 (PyPI) FAIL
kirin-toolchain 0.23.0.dev0 (main @ d600bcce) FAIL

Analysis

During aggressive unrolling of triple-nested for-loops, the constant propagation pass encounters an SSA value (ResultValue[State] from a load statement) that has been deleted but is still referenced by 6 uses in a conditional_branch's then_arguments. This suggests the IR rewrite that deletes the load statement does not properly update or remap the references held by the branch terminator.

Possibly related: PR #632 (ConstProp Early Termination Optimization).

Workaround

Manually unroll the loops so the kernel contains no for-loop constructs.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: compiler passArea: compiler pass related issues.category: bugCategory: this is a bug or something isn't working as expected.

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions