Skip to content

keep_intermediate=True does not faithfully record initial IR received by first pass #2957

Description

@dime10

f.write(canonicalize(stdin=ir, options=self.options))

Can be misleading / source of confusion when debugging a pass run from the frontend, as the first recorded IR shows a different program than the pass pipeline is receiving. Specifically, the first recorded IR (0_circuit.mlir) is a canonicalized version of the program passed to the pass pipeline. For debugging purposes, which is the most common use case for keep_intermediate, it is important that the program is faithfully reproduced during inspection.

Reproducer:

import pennylane as qp

@qp.qjit(
    target="mlir",
    pipelines=[("short", ["builtin.module(apply-transform-sequence)"])],
    keep_intermediate=3,
)
@qp.qnode(qp.device("null.qubit", wires=1))
def circuit():
    @qp.for_loop(0, 10, 1)
    def loop(_):
        qp.S(0)
    loop()
    return qp.probs()

circuit.mlir_opt

Compare the output of circuit/0_circuit.mlir and circuit/1_short/1_ApplyTransformSequencePass.mlir (technically recorded after the first pass but in this case it doesn't do anything so is identical to the input):

    func.func public @circuit() -> tensor<2xf64> attributes {quantum.node} {
      %c1 = arith.constant 1 : index
      %c10 = arith.constant 10 : index
      %c0 = arith.constant 0 : index
      %c0_i64 = arith.constant 0 : i64
      quantum.device shots(%c0_i64) ["..."]
      %0 = quantum.alloc( 1) : !quantum.reg
      %1 = scf.for %arg0 = %c0 to %c10 step %c1 iter_args(%arg1 = %0) -> (!quantum.reg) {
        %4 = quantum.extract %arg1[ 0] : !quantum.reg -> !quantum.bit
        %out_qubits = quantum.custom "S"() %4 : !quantum.bit
        %5 = quantum.insert %arg1[ 0], %out_qubits : !quantum.reg, !quantum.bit
        scf.yield %5 : !quantum.reg
      }
      %2 = quantum.compbasis qreg %1 : !quantum.obs
      %3 = quantum.probs %2 : tensor<2xf64>
      quantum.dealloc %1 : !quantum.reg
      quantum.device_release
      return %3 : tensor<2xf64>
    }

and

  func.func public @circuit() -> tensor<2xf64> attributes {quantum.node} {
    %c = stablehlo.constant dense<0> : tensor<i64>
    %extracted = tensor.extract %c[] : tensor<i64>
    quantum.device shots(%extracted) ["..."]
    %c_0 = stablehlo.constant dense<1> : tensor<i64>
    %0 = quantum.alloc( 1) : !quantum.reg
    %c_1 = stablehlo.constant dense<10> : tensor<i64>
    %extracted_2 = tensor.extract %c[] : tensor<i64>
    %1 = arith.index_cast %extracted_2 : i64 to index
    %extracted_3 = tensor.extract %c_1[] : tensor<i64>
    %2 = arith.index_cast %extracted_3 : i64 to index
    %extracted_4 = tensor.extract %c_0[] : tensor<i64>
    %3 = arith.index_cast %extracted_4 : i64 to index
    %4 = scf.for %arg0 = %1 to %2 step %3 iter_args(%arg1 = %0) -> (!quantum.reg) {
      %7 = arith.index_cast %arg0 : index to i64
      %from_elements = tensor.from_elements %7 : tensor<i64>
      %c_5 = stablehlo.constant dense<0> : tensor<i64>
      %extracted_6 = tensor.extract %c_5[] : tensor<i64>
      %8 = quantum.extract %arg1[%extracted_6] : !quantum.reg -> !quantum.bit
      %out_qubits = quantum.custom "S"() %8 : !quantum.bit
      %extracted_7 = tensor.extract %c_5[] : tensor<i64>
      %9 = quantum.insert %arg1[%extracted_7], %out_qubits : !quantum.reg, !quantum.bit
      scf.yield %9 : !quantum.reg
    }
    %5 = quantum.compbasis qreg %4 : !quantum.obs
    %6 = quantum.probs %5 : tensor<2xf64>
    quantum.dealloc %4 : !quantum.reg
    quantum.device_release
    return %6 : tensor<2xf64>
  }

Metadata

Metadata

Assignees

No one assigned

    Labels

    compilerPull requests that update the compiler

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions