‘qco’ Dialect

The QCO (value semantics) dialect for quantum computing.

The QCO dialect uses value semantics where quantum operations consume input qubits and produce new output values, following the functional programming and SSA paradigm. This model enables:

  • Powerful compiler optimizations through clear dataflow

  • Safe reordering and parallelization analysis

  • Advanced transformation passes

  • Explicit dependency tracking

The name “QCO” stands for “Quantum Circuit Optimization.”

Example:

%q_out = qco.h %q_in                       // Consumes %q_in, produces %q_out
%q0_out, %q1_out = qco.swap %q0_in, %q1_in // Consumes inputs, produces outputs

Operations

source

qco.alloc (qco::AllocOp)

Allocate a qubit dynamically

Syntax:

operation ::= `qco.alloc` attr-dict `:` type($result)

Allocates a new qubit dynamically and returns an SSA value representing it. The qubit is initialized to the |0⟩ state.

Example:

%q = qco.alloc : !qco.qubit

Interfaces: InferTypeOpInterface, MemoryEffectOpInterface (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{MemoryEffects::Allocate on ::mlir::SideEffects::DefaultResource}

Results:

Result

Description

result

QCO qubit value type

qco.barrier (qco::BarrierOp)

Apply a barrier gate to a set of qubits

Syntax:

operation ::= `qco.barrier` $qubits_in attr-dict `:` type($qubits_in) `->` type($qubits_out)

Applies a barrier gate to a set of qubits and returns the transformed qubits.

Example:

%q_out = qco.barrier %q_in : !qco.qubit -> !qco.qubit

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface), UnitaryOpInterface

Effects: MemoryEffects::Effect{}

Operands:

Operand

Description

qubits_in

variadic of QCO qubit value type

Results:

Result

Description

qubits_out

variadic of QCO qubit value type

qco.ctrl (qco::CtrlOp)

Apply a control modifier to a collection of gates

Syntax:

operation ::= `qco.ctrl` `(` $controls_in `)`
              `targets`
              custom<TargetAliasing>($region, $targets_in)
              attr-dict `:`
              `(` `{` type($controls_in) `}` ( `,` `{` type($targets_in)^ `}` )? `)`
              `->`
              `(` `{` type($controls_out) `}` ( `,` `{` type($targets_out)^ `}` )? `)`

A modifier operation that adds control qubits to the gates defined in its body region. The controlled operation applies the controlled gates only when all control qubits are in the \(|1\rangle\) state.

The operation takes a variadic number of control and target qubits as inputs and produces corresponding output qubits. Control qubits are not modified by the operation and simply pass through to the outputs.

The body region may contain an arbitrary amount of unitary and classical operations. Classical SSA values may be captured from above, but every qubit used in the body must be passed through a modifier operand and accessed via its aliased block argument. Non-unitary operations, such as AllocOp and MeasureOp, are not allowed.

Example:

%res_ctrl, %res_tgt:2 = qco.ctrl(%ctrl) targets(%a0 = %q0, %a1 = %q1) {
    %a0_1, %a1_1 = qco.swap %a0, %a1 : !qco.qubit, !qco.qubit -> !qco.qubit, !qco.qubit
    qco.yield %a0_1, %a1_1 : !qco.qubit, !qco.qubit
} : ({!qco.qubit}, {!qco.qubit, !qco.qubit}) -> ({!qco.qubit}, {!qco.qubit, !qco.qubit})

Traits: AlwaysSpeculatableImplTrait, AttrSizedOperandSegments, AttrSizedResultSegments, RecursiveMemoryEffects, SameOperandsAndResultShape, SameOperandsAndResultType, SingleBlockImplicitTerminator<YieldOp>, SingleBlock

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface), UnitaryOpInterface

Effects: MemoryEffects::Effect{}

Operands:

Operand

Description

controls_in

variadic of QCO qubit value type

targets_in

variadic of QCO qubit value type

Results:

Result

Description

controls_out

variadic of QCO qubit value type

targets_out

variadic of QCO qubit value type

qco.dcx (qco::DCXOp)

Apply a DCX gate to two qubits

Syntax:

operation ::= `qco.dcx` $qubit0_in `,` $qubit1_in attr-dict `:` type($qubit0_in) `,` type($qubit1_in) `->` type($qubit0_out) `,` type($qubit1_out)

Applies a DCX gate to two qubits and returns the transformed qubits.

Example:

%q0_out, %q1_out = qco.dcx %q0_in, %q1_in : !qco.qubit, !qco.qubit -> !qco.qubit, !qco.qubit

Traits: AlwaysSpeculatableImplTrait, TwoTargetZeroParameter

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface), UnitaryOpInterface

Effects: MemoryEffects::Effect{}

Operands:

Operand

Description

qubit0_in

QCO qubit value type

qubit1_in

QCO qubit value type

Results:

Result

Description

qubit0_out

QCO qubit value type

qubit1_out

QCO qubit value type

qco.ecr (qco::ECROp)

Apply an ECR gate to two qubits

Syntax:

operation ::= `qco.ecr` $qubit0_in `,` $qubit1_in attr-dict `:` type($qubit0_in) `,` type($qubit1_in) `->` type($qubit0_out) `,` type($qubit1_out)

Applies an ECR gate to two qubits and returns the transformed qubits.

Example:

%q0_out, %q1_out = qco.ecr %q0_in, %q1_in : !qco.qubit, !qco.qubit -> !qco.qubit, !qco.qubit

Traits: AlwaysSpeculatableImplTrait, TwoTargetZeroParameter

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface), UnitaryOpInterface

Effects: MemoryEffects::Effect{}

Operands:

Operand

Description

qubit0_in

QCO qubit value type

qubit1_in

QCO qubit value type

Results:

Result

Description

qubit0_out

QCO qubit value type

qubit1_out

QCO qubit value type

qco.gphase (qco::GPhaseOp)

Apply a global phase to the state

Syntax:

operation ::= `qco.gphase` `(` $theta `)` attr-dict

Applies a global phase to the state.

Constant angles must be finite and have magnitude at most 10000 radians. Dynamic angles have the same runtime precondition.

Example:

qco.gphase(%theta)

Traits: ZeroTargetOneParameter

Interfaces: MemoryEffectOpInterface (MemoryEffectOpInterface), UnitaryOpInterface

Effects: MemoryEffects::Effect{MemoryEffects::Write on ::mlir::SideEffects::DefaultResource}

Operands:

Operand

Description

theta

64-bit float

qco.h (qco::HOp)

Apply a H gate to a qubit

Syntax:

operation ::= `qco.h` $qubit_in attr-dict `:` type($qubit_in) `->` type($qubit_out)

Applies a H gate to a qubit and returns the transformed qubit.

Example:

%q_out = qco.h %q_in : !qco.qubit -> !qco.qubit

Traits: AlwaysSpeculatableImplTrait, OneTargetZeroParameter

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface), UnitaryOpInterface

Effects: MemoryEffects::Effect{}

Operands:

Operand

Description

qubit_in

QCO qubit value type

Results:

Result

Description

qubit_out

QCO qubit value type

qco.id (qco::IdOp)

Apply an Id gate to a qubit

Syntax:

operation ::= `qco.id` $qubit_in attr-dict `:` type($qubit_in) `->` type($qubit_out)

Applies an Id gate to a qubit and returns the transformed qubit.

Example:

%q_out = qco.id %q_in : !qco.qubit -> !qco.qubit

Traits: AlwaysSpeculatableImplTrait, OneTargetZeroParameter

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface), UnitaryOpInterface

Effects: MemoryEffects::Effect{}

Operands:

Operand

Description

qubit_in

QCO qubit value type

Results:

Result

Description

qubit_out

QCO qubit value type

qco.if (qco::IfOp)

If-then-else operation with classical and linear results

The qco.if operation is an if-then-else construct similar to the standard scf.if operation. In addition to the condition, the operation takes a variadic number of qubits and qtensors as inputs that are required in the bodies of both branches. These values are passed down to the individual regions as block arguments. The operation may additionally return ordinary classical SSA values. Classical results precede the linear results. The number and types of the linear results must match the input qubit and qtensor values.

Example:

%flag, %result = qco.if %condition args(%arg0 = %q0)
    -> (i1, !qco.qubit) {
    %q1 = qco.h %arg0 : !qco.qubit -> !qco.qubit
    qco.yield %true, %q1 : i1, !qco.qubit
 } else args(%arg0 = %q0) {
    qco.yield %false, %arg0 : i1, !qco.qubit
}

Traits: AlwaysSpeculatableImplTrait, AttrSizedResultSegments, RecursiveMemoryEffects, SingleBlockImplicitTerminator<YieldOp>, SingleBlock

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface), RegionBranchOpInterface

Effects: MemoryEffects::Effect{}

Operands:

Operand

Description

condition

1-bit signless integer

qubits

variadic of QCO qubit value type or 1D tensor of QCO qubit value type values

Results:

Result

Description

classicalResults

variadic of any type

linearResults

variadic of QCO qubit value type or 1D tensor of QCO qubit value type values

qco.index_switch (qco::IndexSwitchOp)

Index-based switch operation with classical and linear results

The qco.index_switch operation provides multi-way branching based on an index value, analogous to scf.index_switch. In addition to the index, the operation takes a variadic number of qubits and qtensors as inputs that are required in all case branches. These values are passed down to each case region as block arguments. The operation may additionally return ordinary classical SSA values. Classical results precede the linear results. The number and types of the linear results must match the input qubit and qtensor values.

The operation has one region for each case value plus a default region. Each region must terminate with a qco.yield operation that yields values matching the operation’s result types.

Example:

%flag, %result = qco.index_switch %index -> (i1, !qco.qubit)
case 0 args(%arg0 = %q0) {
  %q1 = qco.h %arg0 : !qco.qubit -> !qco.qubit
  qco.yield %true, %q1 : i1, !qco.qubit
}
case 1 args(%arg0 = %q0) {
  %q1 = qco.x %arg0 : !qco.qubit -> !qco.qubit
  qco.yield %false, %q1 : i1, !qco.qubit
}
default args(%arg0 = %q0) {
  qco.yield %false, %arg0 : i1, !qco.qubit
}

Traits: AlwaysSpeculatableImplTrait, AttrSizedResultSegments, RecursiveMemoryEffects, SingleBlockImplicitTerminator<YieldOp>, SingleBlock

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface), RegionBranchOpInterface

Effects: MemoryEffects::Effect{}

Attributes:

AttributeMLIR TypeDescription
cases::mlir::DenseI64ArrayAttri64 dense array attribute

Operands:

Operand

Description

arg

index

targets

variadic of QCO qubit value type or 1D tensor of QCO qubit value type values

Results:

Result

Description

classicalResults

variadic of any type

linearResults

variadic of QCO qubit value type or 1D tensor of QCO qubit value type values

qco.inv (qco::InvOp)

Apply an inverse (i.e., adjoint) modifier to a collection of gates

Syntax:

operation ::= `qco.inv` custom<TargetAliasing>($region, $qubits_in)
              attr-dict
              ( `:` `{` type($qubits_in)^ `}` `->` `{` type($qubits_out) `}` )?

A modifier operation that inverts the gates defined in its body region.

The operation takes a variadic number of qubits as inputs and produces corresponding output qubits.

The body region may contain an arbitrary amount of unitary and classical operations. Classical SSA values may be captured from above, but every qubit used in the body must be passed through a modifier operand and accessed via its aliased block argument. Non-unitary operations, such as AllocOp and MeasureOp, are not allowed.

Example:

%q_out = qco.inv (%q = %q_in) {
    %q_1 = qco.s %q : !qco.qubit -> !qco.qubit
    qco.yield %q_1 : !qco.qubit
} : {!qco.qubit} -> {!qco.qubit}

Traits: AlwaysSpeculatableImplTrait, RecursiveMemoryEffects, SingleBlockImplicitTerminator<YieldOp>, SingleBlock

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface), UnitaryOpInterface

Effects: MemoryEffects::Effect{}

Operands:

Operand

Description

qubits_in

variadic of QCO qubit value type

Results:

Result

Description

qubits_out

variadic of QCO qubit value type

qco.iswap (qco::iSWAPOp)

Apply a iSWAP gate to two qubits

Syntax:

operation ::= `qco.iswap` $qubit0_in `,` $qubit1_in attr-dict `:` type($qubit0_in) `,` type($qubit1_in) `->` type($qubit0_out) `,` type($qubit1_out)

Applies a iSWAP gate to two qubits and returns the transformed qubits.

Example:

%q0_out, %q1_out = qco.iswap %q0_in, %q1_in : !qco.qubit, !qco.qubit -> !qco.qubit, !qco.qubit

Traits: AlwaysSpeculatableImplTrait, TwoTargetZeroParameter

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface), UnitaryOpInterface

Effects: MemoryEffects::Effect{}

Operands:

Operand

Description

qubit0_in

QCO qubit value type

qubit1_in

QCO qubit value type

Results:

Result

Description

qubit0_out

QCO qubit value type

qubit1_out

QCO qubit value type

qco.measure (qco::MeasureOp)

Measure a qubit in the computational basis

Syntax:

operation ::= `qco.measure` $qubit_in `:` type($qubit_in) attr-dict

Measures a qubit in the computational (Z) basis, collapsing the state and returning both the output qubit and a classical bit result.

Example:

%q_out, %result = qco.measure %q_in : !qco.qubit

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

Operand

Description

qubit_in

QCO qubit value type

Results:

Result

Description

qubit_out

QCO qubit value type

result

1-bit signless integer

qco.p (qco::POp)

Apply a P gate to a qubit

Syntax:

operation ::= `qco.p` `(` $theta `)` $qubit_in attr-dict `:` type($qubit_in) `->` type($qubit_out)

Applies a P gate to a qubit and returns the transformed qubit.

Example:

%q_out = qco.p(%theta) %q_in : !qco.qubit -> !qco.qubit

Traits: AlwaysSpeculatableImplTrait, OneTargetOneParameter

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface), UnitaryOpInterface

Effects: MemoryEffects::Effect{}

Operands:

Operand

Description

qubit_in

QCO qubit value type

theta

64-bit float

Results:

Result

Description

qubit_out

QCO qubit value type

qco.pow (qco::PowOp)

Raise a unitary operation to a power

Syntax:

operation ::= `qco.pow` `(` $exponent `)` custom<TargetAliasing>($region, $qubits_in)
              attr-dict
              ( `:` `{` type($qubits_in)^ `}` `->` `{` type($qubits_out) `}` )?

A modifier operation that raises the gates defined in its body region to a given power.

The operation takes a variadic number of qubits as inputs and produces corresponding output qubits.

The exponent can be an integer or a floating-point number.

  • r > 0: apply the gate raised to the r-th power.

  • r = 0: identity (no-op).

  • r < 0: equivalent to inv @ pow(-r) @ g.

The body region may contain an arbitrary amount of unitary and classical operations. Classical SSA values may be captured from above, but every qubit used in the body must be passed through a modifier operand and accessed via its aliased block argument. Non-unitary operations, such as AllocOp and MeasureOp, are not allowed.

Example:

%q_out = qco.pow(%exponent) (%q = %q_in) {
    %q_1 = qco.s %q : !qco.qubit -> !qco.qubit
    qco.yield %q_1
} : {!qco.qubit} -> {!qco.qubit}

Traits: RecursiveMemoryEffects, SingleBlockImplicitTerminator<::mlir::qco::YieldOp>, SingleBlock

Interfaces: UnitaryOpInterface

Operands:

Operand

Description

exponent

64-bit float

qubits_in

variadic of QCO qubit value type

Results:

Result

Description

qubits_out

variadic of QCO qubit value type

qco.r (qco::ROp)

Apply an R gate to a qubit

Syntax:

operation ::= `qco.r` `(` $theta `,` $phi `)` $qubit_in attr-dict `:` type($qubit_in) `->` type($qubit_out)

Applies an R gate to a qubit and returns the transformed qubit.

Example:

%q_out = qco.r(%theta, %phi) %q_in : !qco.qubit -> !qco.qubit

Traits: AlwaysSpeculatableImplTrait, OneTargetTwoParameter

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface), UnitaryOpInterface

Effects: MemoryEffects::Effect{}

Operands:

Operand

Description

qubit_in

QCO qubit value type

theta

64-bit float

phi

64-bit float

Results:

Result

Description

qubit_out

QCO qubit value type

qco.rccx (qco::RCCXOp)

Apply a relative-phase CCX gate to three qubits

Syntax:

operation ::= `qco.rccx` $qubit0_in `,` $qubit1_in `,` $qubit2_in attr-dict `:` type($qubit0_in) `,` type($qubit1_in) `,` type($qubit2_in) `->` type($qubit0_out) `,` type($qubit1_out) `,` type($qubit2_out)

Applies a relative-phase CCX (RCCX) gate to three qubits and returns the transformed qubits.

Example:

%q0_out, %q1_out, %q2_out = qco.rccx %q0_in, %q1_in, %q2_in : !qco.qubit, !qco.qubit, !qco.qubit -> !qco.qubit, !qco.qubit, !qco.qubit

Traits: AlwaysSpeculatableImplTrait, ThreeTargetZeroParameter

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface), UnitaryOpInterface

Effects: MemoryEffects::Effect{}

Operands:

Operand

Description

qubit0_in

QCO qubit value type

qubit1_in

QCO qubit value type

qubit2_in

QCO qubit value type

Results:

Result

Description

qubit0_out

QCO qubit value type

qubit1_out

QCO qubit value type

qubit2_out

QCO qubit value type

qco.reset (qco::ResetOp)

Reset a qubit to |0⟩ state

Syntax:

operation ::= `qco.reset` $qubit_in attr-dict `:` type($qubit_in) `->` type($qubit_out)

Resets a qubit to the |0⟩ state, regardless of its current state, and returns the reset qubit.

Example:

%q_out = qco.reset %q_in : !qco.qubit -> !qco.qubit

Traits: AlwaysSpeculatableImplTrait, Idempotent, SameOperandsAndResultType

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

Operand

Description

qubit_in

QCO qubit value type

Results:

Result

Description

qubit_out

QCO qubit value type

qco.rx (qco::RXOp)

Apply an RX gate to a qubit

Syntax:

operation ::= `qco.rx` `(` $theta `)` $qubit_in attr-dict `:` type($qubit_in) `->` type($qubit_out)

Applies an RX gate to a qubit and returns the transformed qubit.

Example:

%q_out = qco.rx(%theta) %q_in : !qco.qubit -> !qco.qubit

Traits: AlwaysSpeculatableImplTrait, OneTargetOneParameter

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface), UnitaryOpInterface

Effects: MemoryEffects::Effect{}

Operands:

Operand

Description

qubit_in

QCO qubit value type

theta

64-bit float

Results:

Result

Description

qubit_out

QCO qubit value type

qco.rxx (qco::RXXOp)

Apply an RXX gate to two qubits

Syntax:

operation ::= `qco.rxx` `(` $theta `)` $qubit0_in `,` $qubit1_in attr-dict `:` type($qubit0_in) `,` type($qubit1_in) `->` type($qubit0_out) `,` type($qubit1_out)

Applies an RXX gate to two qubits and returns the transformed qubits.

Example:

%q0_out, %q1_out = qco.rxx(%theta) %q0_in, %q1_in : !qco.qubit, !qco.qubit -> !qco.qubit, !qco.qubit

Traits: AlwaysSpeculatableImplTrait, TwoTargetOneParameter

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface), UnitaryOpInterface

Effects: MemoryEffects::Effect{}

Operands:

Operand

Description

qubit0_in

QCO qubit value type

qubit1_in

QCO qubit value type

theta

64-bit float

Results:

Result

Description

qubit0_out

QCO qubit value type

qubit1_out

QCO qubit value type

qco.ry (qco::RYOp)

Apply an RY gate to a qubit

Syntax:

operation ::= `qco.ry` `(` $theta `)` $qubit_in attr-dict `:` type($qubit_in) `->` type($qubit_out)

Applies an RY gate to a qubit and returns the transformed qubit.

Example:

%q_out = qco.ry(%theta) %q_in : !qco.qubit -> !qco.qubit

Traits: AlwaysSpeculatableImplTrait, OneTargetOneParameter

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface), UnitaryOpInterface

Effects: MemoryEffects::Effect{}

Operands:

Operand

Description

qubit_in

QCO qubit value type

theta

64-bit float

Results:

Result

Description

qubit_out

QCO qubit value type

qco.ryy (qco::RYYOp)

Apply an RYY gate to two qubits

Syntax:

operation ::= `qco.ryy` `(` $theta `)` $qubit0_in `,` $qubit1_in attr-dict `:` type($qubit0_in) `,` type($qubit1_in) `->` type($qubit0_out) `,` type($qubit1_out)

Applies an RYY gate to two qubits and returns the transformed qubits.

Example:

%q0_out, %q1_out = qco.ryy(%theta) %q0_in, %q1_in : !qco.qubit, !qco.qubit -> !qco.qubit, !qco.qubit

Traits: AlwaysSpeculatableImplTrait, TwoTargetOneParameter

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface), UnitaryOpInterface

Effects: MemoryEffects::Effect{}

Operands:

Operand

Description

qubit0_in

QCO qubit value type

qubit1_in

QCO qubit value type

theta

64-bit float

Results:

Result

Description

qubit0_out

QCO qubit value type

qubit1_out

QCO qubit value type

qco.rz (qco::RZOp)

Apply an RZ gate to a qubit

Syntax:

operation ::= `qco.rz` `(` $theta `)` $qubit_in attr-dict `:` type($qubit_in) `->` type($qubit_out)

Applies an RZ gate to a qubit and returns the transformed qubit.

Example:

%q_out = qco.rz(%theta) %q_in : !qco.qubit -> !qco.qubit

Traits: AlwaysSpeculatableImplTrait, OneTargetOneParameter

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface), UnitaryOpInterface

Effects: MemoryEffects::Effect{}

Operands:

Operand

Description

qubit_in

QCO qubit value type

theta

64-bit float

Results:

Result

Description

qubit_out

QCO qubit value type

qco.rzx (qco::RZXOp)

Apply an RZX gate to two qubits

Syntax:

operation ::= `qco.rzx` `(` $theta `)` $qubit0_in `,` $qubit1_in attr-dict `:` type($qubit0_in) `,` type($qubit1_in) `->` type($qubit0_out) `,` type($qubit1_out)

Applies an RZX gate to two qubits and returns the transformed qubits.

Example:

%q0_out, %q1_out = qco.rzx(%theta) %q0_in, %q1_in : !qco.qubit, !qco.qubit -> !qco.qubit, !qco.qubit

Traits: AlwaysSpeculatableImplTrait, TwoTargetOneParameter

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface), UnitaryOpInterface

Effects: MemoryEffects::Effect{}

Operands:

Operand

Description

qubit0_in

QCO qubit value type

qubit1_in

QCO qubit value type

theta

64-bit float

Results:

Result

Description

qubit0_out

QCO qubit value type

qubit1_out

QCO qubit value type

qco.rzz (qco::RZZOp)

Apply an RZZ gate to two qubits

Syntax:

operation ::= `qco.rzz` `(` $theta `)` $qubit0_in `,` $qubit1_in attr-dict `:` type($qubit0_in) `,` type($qubit1_in) `->` type($qubit0_out) `,` type($qubit1_out)

Applies an RZZ gate to two qubits and returns the transformed qubits.

Example:

%q0_out, %q1_out = qco.rzz(%theta) %q0_in, %q1_in : !qco.qubit, !qco.qubit -> !qco.qubit, !qco.qubit

Traits: AlwaysSpeculatableImplTrait, TwoTargetOneParameter

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface), UnitaryOpInterface

Effects: MemoryEffects::Effect{}

Operands:

Operand

Description

qubit0_in

QCO qubit value type

qubit1_in

QCO qubit value type

theta

64-bit float

Results:

Result

Description

qubit0_out

QCO qubit value type

qubit1_out

QCO qubit value type

qco.s (qco::SOp)

Apply an S gate to a qubit

Syntax:

operation ::= `qco.s` $qubit_in attr-dict `:` type($qubit_in) `->` type($qubit_out)

Applies an S gate to a qubit and returns the transformed qubit.

Example:

%q_out = qco.s %q_in : !qco.qubit -> !qco.qubit

Traits: AlwaysSpeculatableImplTrait, OneTargetZeroParameter

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface), UnitaryOpInterface

Effects: MemoryEffects::Effect{}

Operands:

Operand

Description

qubit_in

QCO qubit value type

Results:

Result

Description

qubit_out

QCO qubit value type

qco.sdg (qco::SdgOp)

Apply an Sdg gate to a qubit

Syntax:

operation ::= `qco.sdg` $qubit_in attr-dict `:` type($qubit_in) `->` type($qubit_out)

Applies an Sdg gate to a qubit and returns the transformed qubit.

Example:

%q_out = qco.sdg %q_in : !qco.qubit -> !qco.qubit

Traits: AlwaysSpeculatableImplTrait, OneTargetZeroParameter

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface), UnitaryOpInterface

Effects: MemoryEffects::Effect{}

Operands:

Operand

Description

qubit_in

QCO qubit value type

Results:

Result

Description

qubit_out

QCO qubit value type

qco.sink (qco::SinkOp)

Consume a qubit value (end of lifetime)

Syntax:

operation ::= `qco.sink` $qubit attr-dict `:` type($qubit)

Consumes a qubit SSA value and marks the end of its lifetime.

This operation is the canonical “sink” for QCO’s linear/value semantics: every qubit value must be consumed exactly once on all paths.

When converting back to QC (reference semantics), sinks corresponding to static qubits may be erased.

Example:

qco.sink %q : !qco.qubit

Interfaces: MemoryEffectOpInterface (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{MemoryEffects::Free on ::mlir::SideEffects::DefaultResource}

Operands:

Operand

Description

qubit

QCO qubit value type

qco.static (qco::StaticOp)

Retrieve a static qubit by index

Syntax:

operation ::= `qco.static` $index attr-dict `:` type($qubit)

The qco.static operation produces an SSA value representing a qubit identified by a static index. This is useful for referring to fixed qubits in a quantum program or to hardware-mapped qubits.

Example:

%q = qco.static 0 : !qco.qubit

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Attributes:

AttributeMLIR TypeDescription
index::mlir::IntegerAttr64-bit signless integer attribute whose value is non-negative

Results:

Result

Description

qubit

QCO qubit value type

qco.swap (qco::SWAPOp)

Apply a SWAP gate to two qubits

Syntax:

operation ::= `qco.swap` $qubit0_in `,` $qubit1_in attr-dict `:` type($qubit0_in) `,` type($qubit1_in) `->` type($qubit0_out) `,` type($qubit1_out)

Applies a SWAP gate to two qubits and returns the transformed qubits.

Example:

%q0_out, %q1_out = qco.swap %q0_in, %q1_in : !qco.qubit, !qco.qubit -> !qco.qubit, !qco.qubit

Traits: AlwaysSpeculatableImplTrait, TwoTargetZeroParameter

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface), UnitaryOpInterface

Effects: MemoryEffects::Effect{}

Operands:

Operand

Description

qubit0_in

QCO qubit value type

qubit1_in

QCO qubit value type

Results:

Result

Description

qubit0_out

QCO qubit value type

qubit1_out

QCO qubit value type

qco.sx (qco::SXOp)

Apply an SX gate to a qubit

Syntax:

operation ::= `qco.sx` $qubit_in attr-dict `:` type($qubit_in) `->` type($qubit_out)

Applies an SX gate to a qubit and returns the transformed qubit.

Example:

%q_out = qco.sx %q_in : !qco.qubit -> !qco.qubit

Traits: AlwaysSpeculatableImplTrait, OneTargetZeroParameter

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface), UnitaryOpInterface

Effects: MemoryEffects::Effect{}

Operands:

Operand

Description

qubit_in

QCO qubit value type

Results:

Result

Description

qubit_out

QCO qubit value type

qco.sxdg (qco::SXdgOp)

Apply an SXdg gate to a qubit

Syntax:

operation ::= `qco.sxdg` $qubit_in attr-dict `:` type($qubit_in) `->` type($qubit_out)

Applies an SXdg gate to a qubit and returns the transformed qubit.

Example:

%q_out = qco.sxdg %q_in : !qco.qubit -> !qco.qubit

Traits: AlwaysSpeculatableImplTrait, OneTargetZeroParameter

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface), UnitaryOpInterface

Effects: MemoryEffects::Effect{}

Operands:

Operand

Description

qubit_in

QCO qubit value type

Results:

Result

Description

qubit_out

QCO qubit value type

qco.t (qco::TOp)

Apply a T gate to a qubit

Syntax:

operation ::= `qco.t` $qubit_in attr-dict `:` type($qubit_in) `->` type($qubit_out)

Applies a T gate to a qubit and returns the transformed qubit.

Example:

%q_out = qco.t %q_in : !qco.qubit -> !qco.qubit

Traits: AlwaysSpeculatableImplTrait, OneTargetZeroParameter

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface), UnitaryOpInterface

Effects: MemoryEffects::Effect{}

Operands:

Operand

Description

qubit_in

QCO qubit value type

Results:

Result

Description

qubit_out

QCO qubit value type

qco.tdg (qco::TdgOp)

Apply a Tdg gate to a qubit

Syntax:

operation ::= `qco.tdg` $qubit_in attr-dict `:` type($qubit_in) `->` type($qubit_out)

Applies a Tdg gate to a qubit and returns the transformed qubit.

Example:

%q_out = qco.tdg %q_in : !qco.qubit -> !qco.qubit

Traits: AlwaysSpeculatableImplTrait, OneTargetZeroParameter

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface), UnitaryOpInterface

Effects: MemoryEffects::Effect{}

Operands:

Operand

Description

qubit_in

QCO qubit value type

Results:

Result

Description

qubit_out

QCO qubit value type

qco.u (qco::UOp)

Apply a U gate to a qubit

Syntax:

operation ::= `qco.u` `(` $theta `,` $phi `,` $lambda `)` $qubit_in attr-dict `:` type($qubit_in) `->` type($qubit_out)

Applies a U gate to a qubit and returns the transformed qubit.

Example:

%q_out = qco.u(%theta, %phi, %lambda) %q_in : !qco.qubit -> !qco.qubit

Traits: AlwaysSpeculatableImplTrait, OneTargetThreeParameter

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface), UnitaryOpInterface

Effects: MemoryEffects::Effect{}

Operands:

Operand

Description

qubit_in

QCO qubit value type

theta

64-bit float

phi

64-bit float

lambda

64-bit float

Results:

Result

Description

qubit_out

QCO qubit value type

qco.u2 (qco::U2Op)

Apply a U2 gate to a qubit

Syntax:

operation ::= `qco.u2` `(` $phi `,` $lambda `)` $qubit_in attr-dict `:` type($qubit_in) `->` type($qubit_out)

Applies a U2 gate to a qubit and returns the transformed qubit.

Example:

%q_out = qco.u2(%phi, %lambda) %q_in : !qco.qubit -> !qco.qubit

Traits: AlwaysSpeculatableImplTrait, OneTargetTwoParameter

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface), UnitaryOpInterface

Effects: MemoryEffects::Effect{}

Operands:

Operand

Description

qubit_in

QCO qubit value type

phi

64-bit float

lambda

64-bit float

Results:

Result

Description

qubit_out

QCO qubit value type

qco.x (qco::XOp)

Apply an X gate to a qubit

Syntax:

operation ::= `qco.x` $qubit_in attr-dict `:` type($qubit_in) `->` type($qubit_out)

Applies an X gate to a qubit and returns the transformed qubit.

Example:

%q_out = qco.x %q_in : !qco.qubit -> !qco.qubit

Traits: AlwaysSpeculatableImplTrait, OneTargetZeroParameter

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface), UnitaryOpInterface

Effects: MemoryEffects::Effect{}

Operands:

Operand

Description

qubit_in

QCO qubit value type

Results:

Result

Description

qubit_out

QCO qubit value type

qco.xx_minus_yy (qco::XXMinusYYOp)

Apply an XX-YY gate to two qubits

Syntax:

operation ::= `qco.xx_minus_yy` `(` $theta `,` $beta `)` $qubit0_in `,` $qubit1_in attr-dict `:` type($qubit0_in) `,` type($qubit1_in) `->` type($qubit0_out) `,` type($qubit1_out)

Applies an XX-YY gate to two qubits and returns the transformed qubits.

Example:

%q0_out, %q1_out = qco.xx_minus_yy(%theta, %beta) %q0_in, %q1_in : !qco.qubit, !qco.qubit -> !qco.qubit, !qco.qubit

Traits: AlwaysSpeculatableImplTrait, TwoTargetTwoParameter

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface), UnitaryOpInterface

Effects: MemoryEffects::Effect{}

Operands:

Operand

Description

qubit0_in

QCO qubit value type

qubit1_in

QCO qubit value type

theta

64-bit float

beta

64-bit float

Results:

Result

Description

qubit0_out

QCO qubit value type

qubit1_out

QCO qubit value type

qco.xx_plus_yy (qco::XXPlusYYOp)

Apply an XX+YY gate to two qubits

Syntax:

operation ::= `qco.xx_plus_yy` `(` $theta `,` $beta `)` $qubit0_in `,` $qubit1_in attr-dict `:` type($qubit0_in) `,` type($qubit1_in) `->` type($qubit0_out) `,` type($qubit1_out)

Applies an XX+YY gate to two qubits and returns the transformed qubits.

Example:

%q0_out, %q1_out = qco.xx_plus_yy(%theta, %beta) %q0_in, %q1_in : !qco.qubit, !qco.qubit -> !qco.qubit, !qco.qubit

Traits: AlwaysSpeculatableImplTrait, TwoTargetTwoParameter

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface), UnitaryOpInterface

Effects: MemoryEffects::Effect{}

Operands:

Operand

Description

qubit0_in

QCO qubit value type

qubit1_in

QCO qubit value type

theta

64-bit float

beta

64-bit float

Results:

Result

Description

qubit0_out

QCO qubit value type

qubit1_out

QCO qubit value type

qco.y (qco::YOp)

Apply a Y gate to a qubit

Syntax:

operation ::= `qco.y` $qubit_in attr-dict `:` type($qubit_in) `->` type($qubit_out)

Applies a Y gate to a qubit and returns the transformed qubit.

Example:

%q_out = qco.y %q_in : !qco.qubit -> !qco.qubit

Traits: AlwaysSpeculatableImplTrait, OneTargetZeroParameter

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface), UnitaryOpInterface

Effects: MemoryEffects::Effect{}

Operands:

Operand

Description

qubit_in

QCO qubit value type

Results:

Result

Description

qubit_out

QCO qubit value type

qco.yield (qco::YieldOp)

Yield values from a QCO region

Syntax:

operation ::= `qco.yield` attr-dict ($targets^ `:` type($targets))?

Terminates a QCO region. Modifier regions yield their transformed linear values. qco.if and qco.index_switch regions may additionally yield ordinary classical SSA values before their transformed linear values. The operands must match the expected output signature of the parent operation.

Example:

%res_ctrl, %res_tgt:2 = qco.ctrl(%ctrl) targets(%a0 = %q0, %a1 = %q1) {
    %a0_1, %a1_1 = qco.swap %a0, %a1 : !qco.qubit, !qco.qubit -> !qco.qubit, !qco.qubit
    qco.yield %a0_1, %a1_1 : !qco.qubit, !qco.qubit
} : ({!qco.qubit}, {!qco.qubit, !qco.qubit}) -> ({!qco.qubit}, {!qco.qubit, !qco.qubit})

Traits: AlwaysSpeculatableImplTrait, HasParent<CtrlOp, IfOp, IndexSwitchOp, InvOp, PowOp>, ReturnLike, Terminator

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface), RegionBranchTerminatorOpInterface

Effects: MemoryEffects::Effect{}

Operands:

Operand

Description

targets

variadic of any type

qco.z (qco::ZOp)

Apply a Z gate to a qubit

Syntax:

operation ::= `qco.z` $qubit_in attr-dict `:` type($qubit_in) `->` type($qubit_out)

Applies a Z gate to a qubit and returns the transformed qubit.

Example:

%q_out = qco.z %q_in : !qco.qubit -> !qco.qubit

Traits: AlwaysSpeculatableImplTrait, OneTargetZeroParameter

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface), UnitaryOpInterface

Effects: MemoryEffects::Effect{}

Operands:

Operand

Description

qubit_in

QCO qubit value type

Results:

Result

Description

qubit_out

QCO qubit value type

Types

QubitType

QCO qubit value type

Syntax: !qco.qubit

The !qco.qubit type represents an SSA value holding a quantum bit in the QCO dialect. Operations using this type consume input qubits and produce new output qubits following value semantics and the SSA paradigm, enabling powerful dataflow analysis and optimization.

Example:

%q0 = qco.alloc : !qco.qubit
%q1 = qco.h %q0 : !qco.qubit -> !qco.qubit
%q2 = qco.x %q1 : !qco.qubit -> !qco.qubit

OpInterface definitions

UnitaryOpInterface (UnitaryOpInterface)

This interface provides a unified API for all operations that apply or produce a unitary transformation in the QCO dialect. This includes base gates, user-defined gates, modifier operations (control, inverse, power), and sequences.

The interface enables uniform introspection and composition capabilities across all unitary operations with value semantics.

Methods:

getNumQubits
size_t getNumQubits();

Returns the number of qubits acted on by the unitary operation.

NOTE: This method must be implemented by the user.

getNumTargets
size_t getNumTargets();

Returns the number of target qubits (excluding control qubits).

NOTE: This method must be implemented by the user.

getNumControls
size_t getNumControls();

Returns the number of control qubits (both positive and negative).

NOTE: This method must be implemented by the user.

getInputQubit
Value getInputQubit(size_t i);

Returns the i-th input qubit (targets + controls combined).

NOTE: This method must be implemented by the user.

getInputQubits
OperandRange getInputQubits();

Returns a range of all input qubits (targets + controls combined).

NOTE: This method must be implemented by the user.

getOutputQubit
Value getOutputQubit(size_t i);

Returns the i-th output qubit (targets + controls combined).

NOTE: This method must be implemented by the user.

getOutputQubits
ResultRange getOutputQubits();

Returns a range of all output qubits (targets + controls combined).

NOTE: This method must be implemented by the user.

getInputTarget
Value getInputTarget(size_t i);

Returns the i-th target input qubit.

NOTE: This method must be implemented by the user.

getInputTargets
OperandRange getInputTargets();

Returns a range of all target input qubits.

NOTE: This method must be implemented by the user.

getOutputTarget
Value getOutputTarget(size_t i);

Returns the i-th target output qubit.

NOTE: This method must be implemented by the user.

getOutputTargets
ResultRange getOutputTargets();

Returns a range of all target output qubits.

NOTE: This method must be implemented by the user.

getInputControl
Value getInputControl(size_t i);

Returns the i-th control input qubit.

NOTE: This method must be implemented by the user.

getInputControls
OperandRange getInputControls();

Returns a range of all control input qubits.

NOTE: This method must be implemented by the user.

getOutputControl
Value getOutputControl(size_t i);

Returns the i-th control output qubit.

NOTE: This method must be implemented by the user.

getOutputControls
ResultRange getOutputControls();

Returns a range of all control output qubits.

NOTE: This method must be implemented by the user.

getInputForOutput
Value getInputForOutput(Value output);

Returns the input qubit corresponding to the given output qubit.

NOTE: This method must be implemented by the user.

getOutputForInput
Value getOutputForInput(Value input);

Returns the output qubit corresponding to the given input qubit.

NOTE: This method must be implemented by the user.

getNumParams
size_t getNumParams();

Returns the number of parameters.

NOTE: This method must be implemented by the user.

getParameter
Value getParameter(size_t i);

Returns the i-th parameter.

NOTE: This method must be implemented by the user.

getParameters
OperandRange getParameters();

Returns a range of all parameters.

NOTE: This method must be implemented by the user.

isControlled
bool isControlled();

Returns true if the operation has any control qubits, otherwise false.

isSingleQubit
bool isSingleQubit();

Returns true if the operation only acts on a single qubit.

isTwoQubit
bool isTwoQubit();

Returns true if the operation acts on two qubits.

getBaseSymbol
StringRef getBaseSymbol();

Returns the base symbol/mnemonic of the operation.

NOTE: This method must be implemented by the user.

hasCompileTimeKnownUnitaryMatrix
bool hasCompileTimeKnownUnitaryMatrix();

Returns true if the operation has a compile-time known unitary matrix representation, false otherwise.

NOTE: This method must be implemented by the user.

getUnitaryMatrix1x1
bool getUnitaryMatrix1x1(Matrix1x1&out);

Populates the given 1x1 unitary matrix if possible.

getUnitaryMatrix2x2
bool getUnitaryMatrix2x2(Matrix2x2&out);

Populates the given 2x2 unitary matrix if possible.

getUnitaryMatrix4x4
bool getUnitaryMatrix4x4(Matrix4x4&out);

Populates the given 4x4 unitary matrix if possible.

getUnitaryMatrixDynamic
bool getUnitaryMatrixDynamic(DynamicMatrix&out);

Populates the given dynamic unitary matrix.

Passes

-decompose-multi-controlled

Decompose controlled X/Z/phase/SWAP gates and qco.rccx that act on at least min-qubits qubits

Decomposes multi-qubit controlled operations that act on at least min-qubits qubits (default 3: everything wider than a two-qubit gate). Supported shapes: qco.ctrl with a qco.x, qco.z, qco.swap, or constant-angle qco.p body, and qco.rccx.

Family

Width (qubits)

Decomposition

X/Z

3

Elementary CCX/CCZ; rccx when min-qubits is at most 3

X/Z

4

Elementary CCCX/CCCZ

X/Z

5

Specialized ancilla-free relative-phase C^4(Z)

X/Z

6–33

da Silva-Park SP22 MCP(π) core (H · MCP(π) · H for X)

X/Z

≥34

Huang-Palsberg (HP24) borrowed-helper synthesis with a compile-time CX policy table

Phase

3

Optimized C^2(P)

Phase

4–5

Vale (Barenco-relative residual)

Phase

≥6

da Silva-Park SP22 linear-depth

Phase

any (±π)

Routed through the Z path

SWAP

min-qubits

MCSWAP(C, a, b) = CX(a,b) · MCX(C {b}, a) · CX(a,b)

Width is the total number of qubits the gate acts on (controls plus targets).

For controlled SWAP, C {b} is the original control set together with SWAP target b, and the MCX target is the other SWAP qubit a. The emitted MCX is then lowered by the X path under the same min-qubits threshold.

Intermediate building blocks may be left as qco.ctrl / qco.rccx when min-qubits keeps them; the greedy rewriter lowers further when the threshold allows.

Options

-min-qubits : Decompose controlled X/Z/phase/SWAP gates and qco.rccx that act on at least this many qubits (must be at least 3; default 3 means wider than two-qubit).

-fuse-single-qubit-unitary-runs

Fuse single-qubit unitary runs using Euler resynthesis

Matches maximal runs of consecutive single-qubit unitary operations on the same qubit wire (anchored at each run head), composes their constant unitary matrices, and replaces a run with an equivalent sequence of basis gates when beneficial: when the run contains a gate outside the target basis, or when Euler resynthesis would shorten it (synthesizeUnitary1QEuler). Runs that are already in the target basis and no shorter than the canonical synthesis length are left unchanged.

The emitted basis is controlled via the basis option (e.g. zyz, zsxx). A gphase correction is inserted when needed so the rewritten sequence matches the composed matrix exactly (not only up to global phase).

Currently, only operations whose unitary matrix can be obtained at compile time are fused.

Options

-basis : Target Euler basis (zyz, zxz, xzx, xyx, u, zsxx, r).

-hadamard-lifting

This pass attempts to move Hadamard gates as far away from measurements as possible by commuting them with Pauli gates. This is done in order to apply measurement lifting more efficiently, which is a sub-routine of qubit reuse. Additionally, it can change target and control qubits from Pauli-Z gates to make Hadamard lifting applicable. It also lifts Hadamard gates over CNOT gates if that moves a measurement directly after a control.

This pass lifts Hadamard gates away from the measurements in order to apply measurement lifting more effectively. Measurement lifting is a subroutine of the qubit reuse routine. The goal is to measure qubits earlier in the circuit to reuse them and to potentially remove some quantum gates.

Measurement lifting commutes measurements with Pauli and phase gates. However, the routine stops if a Hadamard gate is applied before the measurement takes place. Hadamard lifting attempts to move Hadamards further in front of the circuit, in order to improve the results provided by measurement lifting.

Hadamard lifting uses the following commutation rules:

     ┌───┐ ┌───┐      ┌───┐ ┌───┐
    ─┤ X ├─┤ H ├─ => ─┤ H ├─┤ Z ├─
     └───┘ └───┘      └───┘ └───┘
     ┌───┐ ┌───┐      ┌───┐ ┌───┐
    ─┤ Z ├─┤ H ├─ => ─┤ H ├─┤ X ├─
     └───┘ └───┘      └───┘ └───┘
     ┌───┐ ┌───┐      ┌───┐ ┌───┐                                ┌───────┐
    ─┤ Y ├─┤ H ├─ => ─┤ H ├─┤ Y ├─, while adding a global phase: │ G(pi) │
     └───┘ └───┘      └───┘ └───┘                                └───────┘

Hadamard lifting is only applied to commute Hadamard gates further in front in the circuit, not the other way around. A global phase is added if the Hadamard gate is commuted with a Pauli-Y gate, as YH = -HY.

The routine is only applied to non-controlled Pauli and Hadamard gates.

In order to reduce multi-qubit gates, a second transformation routine is applied. Using the commutation rule

             ┌───┐┌───┐┌───┐
    ──■──    ┤ H ├┤ X ├┤ H ├
    ┌─┴─┐ => │───│└─┬─┘│───│
    ┤ X ├    ┤ H ├──■──┤ H ├
    └───┘    └───┘     └───┘

the following transformation is applied to circuits where a Hadamard gate follows a target gate of a controlled Pauli-X gate, which is followed by a measurement:

                          ┌───┐┌───┐┌───┐
    ──■─────────────      ┤ H ├┤ X ├┤ H ├──
    ┌─┴─┐┌───┐┌──────┐ => │───│└─┬─┘│───┘──┐
    ┤ X ├┤ H ├┤ Meas │    ┤ H ├──■──┤ Meas │
    └───┘└───┘└──────┘    └───┘     └──────┘

Afterward the measurement lifting routine could transform the CNOT into a classically controlled Pauli-X.

-measurement-lifting

Move measurements before compatible unitary operations

This pass moves computational-basis measurements toward the start of a circuit. A measurement of a control can move before the controlled operation. A single-qubit diagonal operation immediately before a measurement is removed because it cannot affect either the outcome or the post-measurement qubit. Multi-qubit diagonal operations are only commuted: removing them could discard phase kickback on another qubit. Measurements also move before x and y, with the classical result inverted.

Earlier measurements enable qubit reuse and subsequent optimizations.

-merge-single-qubit-rotation-gates

Merge single-qubit gates using quaternion-based fusion

Merges consecutive mergeable single-qubit gates acting on the same qubit into a single equivalent U gate, reducing circuit depth and gate count.

Supported gate types: rx, ry, rz, p, r, u2, u, x, y, z, h, s, sdg, t, tdg, sx, sxdg, and id.

The pass greedily collects the longest possible chain of consecutive mergeable gates. Each gate is converted to a unit quaternion:

  • rx, ry, rz, p: single-axis rotations via half-angle formulas.

  • x, y, z: fixed-axis pi rotations (rx/ry/rz).

  • s / sdg: rz(+/- pi / 2); t / tdg: rz(+/- pi / 4).

  • sx / sxdg: rx(+/- pi / 2).

  • h: a pi rotation around the (x + z) / sqrt(2) axis.

  • id: the identity quaternion.

  • r(theta, phi): rotation by theta around axis (cos(phi), sin(phi), 0).

  • u2(phi, lambda) = u(pi / 2, phi, lambda).

  • u(theta, phi, lambda): ZYZ decomposition rz(phi) * ry(theta) * rz(lambda), each factor converted to a quaternion and merged via the Hamilton product.

The gates are then folded one by one via the Hamilton product into a single quaternion, which is decomposed back into ZYZ Euler angles and emitted as a single UOp, representing the same unitary as the input chain. The global phase of each gate is tracked alongside and combined together (x/y/z/h: pi / 2; s/sx: pi / 4; sdg/sxdg: -pi / 4; t/tdg: +/- pi / 8; id and pure SU(2) rotations: 0; p(theta): theta / 2; u/u2: (phi + lambda) / 2).

When every angle in the chain is a compile-time constant, the same algorithm runs on host scalars and emits constant U / gphase results directly. Otherwise it emits arith / math operations that compute the merged parameters at run time.

The emitted UOp is defined by \(U = \exp [i (\phi + \lambda) / 2] R_z (\phi) R_y (\theta) R_z (\lambda)\). Normalizing either extracted Z angle into \([-\pi, \pi)\) by \(\pm 2\pi\) flips the \(\mathrm{SU}(2)\) representative; half of each removed angle is returned as an Euler-wrap phase correction. Each merge therefore computes \(\mathrm{inputPhase} - (\phi + \lambda) / 2 + \mathrm{eulerPhase}\), which restores exact matrix equality (including global phase). This applies even to chains of purely \(\mathrm{SU}(2)\) gates (rx, ry, rz, r). On the host (static) path, a near-zero correction may be omitted; on the SSA (dynamic) path a GPhaseOp is always emitted. After greedy merging, the implementation directly invokes the shared global-phase normalization utility to combine, normalize, and remove trivial corrections in their respective scopes.

-place-and-route

This pass ensures that a program meets the connectivity constraints of a target architecture.

This pass maps top-level scalar and tensor-backed dynamically allocated qubits in a quantum program to the static sites of a CompilerTarget. It uses only the target’s undirected coupling topology: arbitrary one-qubit operations pass through, and every two-qubit operation is routed to adjacent target vertices. Higher-arity unitaries must be decomposed before mapping. Target-defined site identifiers are retained in the resulting qco.static operations.

First, the pass assigns static qubits to the dynamically allocated ones by creating an initial dynamic-to-static mapping, which is referred to as the initial layout. The layout covers the complete target virtually, while only program qubits and vacant sites used as routing workspace are materialized. Then, the pass traverses the circuit and inserts qco.swap operations to ensure that all two-qubit operations are executable on the target architecture, a process known as routing.

For routing, the pass first divides the circuit into layers. A layer is a set of independently executable (sequences or blocks of) two-qubit operations. Subsequently, the pass performs an A* search for each layer to find and insert a sequence of SWAP operations that makes these two-qubit operations executable. The A* search also considers subsequent layers, which are determined by the nlookahead parameter.

The cost function of the A* search is defined as follows:

  • f(n) = g(n) + h(n)

  • g(n) = alpha * depth(n)

  • h(n) = sum(pow(lambda, i) * h(L, p) for [i, L] in enumerate(layers))

Where:

  • p is the dynamic-to-static mapping associated with search node n.

  • layers is an array of layers with size 1 + nlookahead.

  • depth(n) returns the distance from the node n to the root node.

  • dist(i, j) returns the distance between the qubits i and j on the target’s coupling graph.

  • h(L, p) := sum(dist(p[gate.first], p[gate.second]) for gate in L)

To iteratively refine the mapping, the pass performs multiple forward and backward traversals of the circuit. In each traversal, the pass routes the circuit and updates the dynamic-to-static mapping based on the routing decisions made during that traversal. By performing multiple traversals, the pass can iteratively refine the mapping and potentially find a more optimal solution. This is behavior is controlled by the niterations parameter.

The pass option ntrials determines how many random initial layouts the pass explores. If compiled with multi-threading on, these trials will be executed in parallel.

Options

-nlookahead  : The number of lookahead steps.
-alpha       : The alpha factor in the cost function. Must be > 0.
-lambda      : The lambda factor in the cost function.
-niterations : The number of forwards and backwards traversal to improve the initial layout. Must be > 0.
-ntrials     : The number of (possibly parallel) random trials of the forwards and backwards mechanism. Must be > 0.
-seed        : A seed used for randomization.

Statistics

num-inserted-swaps : The number of inserted SWAPs

-quantum-loop-unroll

Unroll bounded loops containing quantum operations

This pass unrolls scf.for operations which contain quantum operations. Classical loops are not unrolled.

Because the pass uses the mlir::loopUnrollByFactor utility internally, the same assumptions and restrictions hold for both. See the MLIR documentation for more information.

Options

-unroll-factor : Use this unroll factor for all loops being unrolled, set it to -1, and it will fully unroll.

-replace-classical-controls

Replace measured controls and diagonal targets with classical data flow

This pass rewrites a qco.ctrl that immediately consumes one or more measured controls into one qco.if. Multiple measurement outcomes are combined into the condition, while unmeasured controls remain quantum controls inside it. The controlled body is not duplicated.

The pass also simplifies supported diagonal operations with measured targets. A measured rz target becomes an outcome-dependent phase on the controls. One measured rzz target turns the operation into an outcome-dependent rz on the other target; two measured targets leave only phase kickback on coherent controls. If every participating qubit has been measured, the diagonal operation is removed. Other single-target phase gates can exchange a measured target with an unmeasured control before the general rewrite.

Replacing quantum controls with classical conditions reduces quantum interactions and can enable qubit reuse and subsequent optimizations.

-reuse-qubits

This pass attempts to utilize qubit reuse to reduce the number of resources required for a quantum program. It does so by looking for qubits that do not interact with each other directly or indirectly and attempting to reset and reuse one of them for the other. By combining this pass with the measurement-lifting and replace-classical-controls passes, it is possible to reduce the number of qubits required for a quantum program significantly.

This pass searches for qubits that do not interact with each other directly or indirectly and attempts to reset and reuse one of them for the other. Improved results can be achieved by combining this pass with the measurement-lifting and replace-classical-controls passes, which can reduce the number of qubits required for a quantum program significantly. Only single-qubit allocations are considered for reuse, no qtensor allocations.

Use the mqt-qubit-reuse pipeline to run the preparation passes followed by this pass.