> ## Documentation Index
> Fetch the complete documentation index at: https://docs.qbraid.com/llms.txt
> Use this file to discover all available pages before exploring further.

# QIR to Squin

This module enables conversion from Quantum Intermediate Representation ([PyQIR](https://github.com/qir-alliance/pyqir)) to Squin kernels, allowing you to execute QIR circuits using the [Bloqade](https://github.com/QuEraComputing/bloqade) SDK's Squin execution engine. [Squin](https://bloqade.quera.com/dev/digital/dialects_and_kernels/squin/) provides a high-performance quantum circuit execution environment, and this conversion opens the door to running QIR circuits on Bloqade simulators and hardware backends.

## Installation

```shell theme={null}
pip install 'qbraid-qir[squin]'
```

## Conversions

This section highlights the different ways in which the converter `load()` can be used with various formats and input types. Each conversion method is demonstrated with practical examples below.

### PyQIR String to Squin kernel

Convert PyQIR `IR string` to a Squin kernel:

<CodeGroup>
  ```python Code theme={null}
  from qbraid_qir.squin import load

  qir_str = """
  ; ModuleID = 'bell'
  source_filename = "bell"

  %Qubit = type opaque

  define void @main() #0 {
  entry:
    call void @__quantum__qis__h__body(%Qubit* null)
    call void @__quantum__qis__cnot__body(%Qubit* null, %Qubit* inttoptr (i64 1 to %Qubit*))
    ret void
  }

  declare void @__quantum__qis__h__body(%Qubit*)

  declare void @__quantum__qis__cnot__body(%Qubit*, %Qubit*)

  attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="custom" "required_num_qubits"="2" "required_num_results"="2" }

  !llvm.module.flags = !{!0, !1, !2, !3}

  !0 = !{i32 1, !"qir_major_version", i32 1}
  !1 = !{i32 7, !"qir_minor_version", i32 0}
  !2 = !{i32 1, !"dynamic_qubit_management", i1 false}
  !3 = !{i32 1, !"dynamic_result_management", i1 false}
  """

  squin_kernel = load(qir_str, kernel_name="bell")
  squin_kernel.print()

  ```

  ```output Output theme={null}
  func.func @bell() -> !py.NoneType {
    ^0(%bell_self):
    │ %0 = func.invoke new() : !py.Qubit maybe_pure=False
    │ %1 = func.invoke new() : !py.Qubit maybe_pure=False
    │ %2 = func.invoke h(%0) : !py.NoneType maybe_pure=False
    │ %3 = func.invoke cx(%0, %1) : !py.NoneType maybe_pure=False
    │ %4 = func.const.none() : !py.NoneType
    │      func.return %4
  } // func.func bell
  ```
</CodeGroup>

### PyQIR Module to Squin kernel

Convert a PyQIR `Module` object to a Squin kernel:

<CodeGroup>
  ```python Code theme={null}
  from qbraid_qir.squin import load
  from pyqir import BasicQisBuilder, SimpleModule

  mod = SimpleModule("ghz", num_qubits=3, num_results=3)
  qis = BasicQisBuilder(mod.builder)

  qis.h(mod.qubits[0])
  qis.cx(mod.qubits[0], mod.qubits[1])
  qis.cx(mod.qubits[1], mod.qubits[2])

  squin_kernel = load(mod._module)
  squin_kernel.print()

  ```

  ```output Output theme={null}
  func.func @main() -> !py.NoneType {
    ^0(%main_self):
    │ %0 = func.invoke new() : !py.Qubit maybe_pure=False
    │ %1 = func.invoke new() : !py.Qubit maybe_pure=False
    │ %2 = func.invoke new() : !py.Qubit maybe_pure=False
    │ %3 = func.invoke h(%0) : !py.NoneType maybe_pure=False
    │ %4 = func.invoke cx(%0, %1) : !py.NoneType maybe_pure=False
    │ %5 = func.invoke cx(%1, %2) : !py.NoneType maybe_pure=False
    │ %6 = func.const.none() : !py.NoneType
    │      func.return %6
  } // func.func main
  ```
</CodeGroup>

### Conversion from File

Load PyQIR IR from a `file` (`.ll` for LLVM IR text or `.bc` for LLVM bitcode):

```python Code theme={null}
from qbraid_qir.squin import load

# Load from .ll file (LLVM IR text)
kernel = load("path/to/circuit.ll", kernel_name="my_circuit")

# Load from .bc file (LLVM bitcode)
kernel = load("path/to/circuit.bc", kernel_name="my_circuit")
```

### Integration with OpenQASM 3

Convert `OpenQASM3` programs to Squin kernels using `qbraid-qir`:

<CodeGroup>
  ```python Code theme={null}
  from qbraid_qir.qasm3 import qasm3_to_qir
  from qbraid_qir.squin import load

  program = """
  OPENQASM 3;
  include "stdgates.inc";
  qubit[2] q;
  bit[2] c;
  h q[0];
  x q[0], q[1];
  rx(pi/2) q[0];
  """

  module = qasm3_to_qir(program, name="my_program")

  squin_kernel = load(str(module))

  squin_kernel.print()

  ```

  ```output Output theme={null}
  func.func @main() -> !py.NoneType {
    ^0(%main_self):
    │ %0 = func.invoke new() : !py.Qubit maybe_pure=False
    │ %1 = func.invoke new() : !py.Qubit maybe_pure=False
    │ %2 = func.invoke h(%0) : !py.NoneType maybe_pure=False
    │ %3 = func.invoke x(%0) : !py.NoneType maybe_pure=False
    │ %4 = func.invoke x(%1) : !py.NoneType maybe_pure=False
    │ %5 = py.constant.constant 1.5707963267948966 : !py.float
    │ %6 = func.invoke rx(%5, %0) : !py.NoneType maybe_pure=False
    │ %7 = func.const.none() : !py.NoneType
    │      func.return %7
  } // func.func main
  ```
</CodeGroup>

### Integration with CUDA-Q

Convert `CUDA-Q` kernels to Squin kernels

```python Code theme={null}
import cudaq
from qbraid_qir.squin import load

@cudaq.kernel
def bell():
    q = cudaq.qvector(2)
    h(q[0])
    cx(q[0], q[1])

# Generate QIR from kernel
qir_str = cudaq.translate(bell, format="qir-base")

squin_kernel = load(qir_str, kernel_name="bell")
squin_kernel.print()
```

<Note>
  **CUDA-Q** is capable of exporting QIR using multiple profiles (such
  as`qir-base, qir-adaptive,` etc.). Currently, the qbraid-qir Squin integration
  supports only QIR generated with the **qir-base** profile. Ensure that when
  using **cudaq.translate**, you specify **format="qir-base"** for
  compatibility.
</Note>

### Using Qubit Register as Argument

Create a kernel that accepts a qubit register as an argument, enabling composition of kernel functions:

<CodeGroup>
  ```python Code theme={null}
  from qbraid_qir.squin import load
  from pyqir import BasicQisBuilder, SimpleModule

  mod = SimpleModule("main", num_qubits=3, num_results=3)
  qis = BasicQisBuilder(mod.builder)
  qis.h(mod.qubits[0])
  qis.cx(mod.qubits[0], mod.qubits[1])

  squin_kernel = load(
  module=mod._module,
  kernel_name="bell",
  register_as_argument=True,
  register_argument_name="qreg"
  )
  squin_kernel.print()

  ```

  ```output Output theme={null}
  func.func @bell(qreg : !py.IList[!py.Qubit, Literal(2,int)]) -> !py.NoneType {
    ^0(%bell_self, %qreg):
    │ %0 = py.constant.constant 0 : !py.int
    │ %1 = py.indexing.getitem(%qreg : !py.IList[!py.Qubit, Literal(2,int)], %0) : !py.Qubit
    │ %2 = py.constant.constant 1 : !py.int
    │ %3 = py.indexing.getitem(%qreg : !py.IList[!py.Qubit, Literal(2,int)], %2) : !py.Qubit
    │ %4 = func.invoke h(%1) : !py.NoneType maybe_pure=False
    │ %5 = func.invoke cx(%1, %3) : !py.NoneType maybe_pure=False
    │ %6 = func.const.none() : !py.NoneType
    │      func.return %6
  } // func.func bell
  ```
</CodeGroup>

## Supported Gates

The following gates are currently supported for conversion from PyQIR to Squin kernels:

| QIR Gate                     | Squin Gate    | Description            |
| ---------------------------- | ------------- | ---------------------- |
| `__quantum__qis__h__body`    | `squin.h`     | Hadamard gate          |
| `__quantum__qis__x__body`    | `squin.x`     | Pauli-X gate           |
| `__quantum__qis__y__body`    | `squin.y`     | Pauli-Y gate           |
| `__quantum__qis__z__body`    | `squin.z`     | Pauli-Z gate           |
| `__quantum__qis__s__body`    | `squin.s`     | S gate (π/2 phase)     |
| `__quantum__qis__t__body`    | `squin.t`     | T gate (π/4 phase)     |
| `__quantum__qis__s__adj`     | `squin.s_adj` | S† gate (adjoint S)    |
| `__quantum__qis__t__adj`     | `squin.t_adj` | T† gate (adjoint T)    |
| `__quantum__qis__rx__body`   | `squin.rx`    | Rotation around X-axis |
| `__quantum__qis__ry__body`   | `squin.ry`    | Rotation around Y-axis |
| `__quantum__qis__rz__body`   | `squin.rz`    | Rotation around Z-axis |
| `__quantum__qis__cnot__body` | `squin.cx`    | Controlled-NOT gate    |
| `__quantum__qis__cz__body`   | `squin.cz`    | Controlled-Z gate      |

## Next Steps

Our current implementation provides comprehensive support for standard QIR gates and circuit conversion. We are actively working on expanding functionality in the following areas:

* **Measurement operations**: Support for measurement operations is planned for a future release.
* **Classical control flow**: Conditional gates and classical control flow are on our roadmap.
* **Custom gates**: We currently support all standard QIR gates listed in the [Supported Gates](#supported-gates) table, with plans to extend support for custom gate definitions.
