diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 4896421f..030da31b 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -42,7 +42,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
- python-version: ['3.10', '3.11', '3.12']
+ python-version: ['3.10', '3.11', '3.12', '3.13']
steps:
- uses: actions/checkout@v6
@@ -58,11 +58,28 @@ jobs:
path: dist
- name: Install package wheel with extras
run: |
+ pip install --upgrade pip
pip install setuptools
- bin/install_wheel_extras.sh dist --extra qasm3 --extra cirq --extra test --extra squin
- - name: Run tests with coverage
+ pip install -r requirements-test.txt
+ bin/install_wheel_extras.sh dist --extra qasm3 --extra cirq --extra squin
+ - name: Run tests with pyqir 0.11.x (typed pointers)
run: |
- pytest --cov=qbraid_qir tests/ --cov-report=html --cov-report=xml --cov-report=term
+ pip install "pyqir>=0.10.0,<0.12"
+ pytest tests/ --cov=qbraid_qir --cov-report=term --cov-report= --cov-config=pyproject.toml -q
+ pip install coverage
+ mkdir -p cov_runs
+ python -m coverage combine --data-file=cov_runs/.coverage.run1 .coverage
+ - name: Run tests with pyqir 0.12+ (opaque pointers)
+ run: |
+ pip install "pyqir>=0.12.0,<0.13.0"
+ pytest tests/ --cov=qbraid_qir --cov-report=term --cov-report= --cov-config=pyproject.toml -q
+ python -m coverage combine --data-file=cov_runs/.coverage.run2 .coverage
+ - name: Combine coverage and generate report
+ run: |
+ python -m coverage combine cov_runs/.coverage.run1 cov_runs/.coverage.run2
+ python -m coverage report
+ mkdir -p build/coverage
+ python -m coverage xml -o build/coverage/coverage.xml
- name: Upload coverage to Codecov
if: matrix.python-version == '3.11'
uses: codecov/codecov-action@v5.5.1
@@ -70,32 +87,4 @@ jobs:
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: false
files: ./build/coverage/coverage.xml
- verbose: true
-
- test-cudaq-to-squin:
- if: github.event.pull_request.draft == false
- needs: build
- runs-on: ubuntu-latest
- strategy:
- matrix:
- python-version: ['3.11']
-
- steps:
- - uses: actions/checkout@v5
- - name: Set up Python ${{ matrix.python-version }}
- uses: actions/setup-python@v6
- with:
- python-version: ${{ matrix.python-version }}
- cache: pip
- - name: Download built package
- uses: actions/download-artifact@v5
- with:
- name: built-package
- path: dist
- - name: Install package wheel with squin and test extras
- run: |
- pip install setuptools
- bin/install_wheel_extras.sh dist --extra squin --extra test
- - name: Run CUDAQ to Squin tests
- run: |
- pytest tests/squin_qir/test_cudaq_to_squin.py -v
\ No newline at end of file
+ verbose: true
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c1a9d193..57881e1b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,64 +14,34 @@ Types of changes:
## [Unreleased]
-### ➕ New Features
-- Added a QIR to `squin` conversion method which allows users to execute QIR programs on `squin` enabled backends. This feature also opens up the Squin representation to many formats such as QASM, and Cirq using the built in qbraid-qir converters. Eg. - ([#252](https://github.com/qBraid/qbraid-qir/pull/252))
-
-```python
-# Converting a PyQIR module to squin
-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:
-```stdout
-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
-
-```
+### ➕ New Features
+- **PyQIR 0.12+ support**: Add compatibility for pyqir 0.12+ (opaque pointers / QIR 2.0) alongside existing 0.10.x support. New `_pyqir_compat` module provides `pointer_id`, `qubit_pointer_type`, and `pyqir_uses_opaque_pointers()` for version-agnostic code. ([#265](https://github.com/qBraid/qbraid-qir/pull/265))
### 🌟 Improvements
-- Split `qbraid_qir.profile` into `qbraid_qir.module` and `qbraid_qir.visitor` ([#237](https://github.com/qBraid/qbraid-qir/pull/237))
-- Improved circuit pre-processing for Cirq converter using Cirq's built-in `optimize_for_target_gateset` ([#248](https://github.com/qBraid/qbraid-qir/pull/248))
-
-- Fix types in the `cirq` converter ([#255](https://github.com/qBraid/qbraid-qir/pull/255))
+- **Backward-compatible PyQIR usage**: Cirq, QASM3, and Squin visitors use the compat layer so the codebase works with both pyqir <0.12 (typed pointers) and ≥0.12 (opaque pointers). ([#265](https://github.com/qBraid/qbraid-qir/pull/265))
+- **Version-aware tests**: Test helpers and fixtures choose typed vs opaque pointer expectations based on the installed pyqir version; added version-specific LL fixtures (e.g. `*_typed.ll`, `*_opaque.ll`) for Cirq and QASM3 tests. ([#265](https://github.com/qBraid/qbraid-qir/pull/265))
+- **CI: test both PyQIR versions**: GitHub Actions test job runs the full suite with pyqir 0.10.x and 0.12+, then combines coverage and uploads to Codecov. ([#265](https://github.com/qBraid/qbraid-qir/pull/265))
+- **Tox: dual PyQIR envs**: New `unit-tests-pyqir10` and `unit-tests-pyqir12` tox environments so `tox` runs unit tests against both pyqir version ranges.
+- **Optional test deps**: Skip cudaq-to-Squin tests when cudaq is not installed; skip autoqasm converter tests when autoqasm is not installed. ([#265](https://github.com/qBraid/qbraid-qir/pull/265))
### 📜 Documentation
-- Factor out docs deps into its own requirements file ([#237](https://github.com/qBraid/qbraid-qir/pull/237))
+
+- **CHANGELOG**: Clarified "Past releases" section with a short description and link to the Releases page. ([#265](https://github.com/qBraid/qbraid-qir/pull/265))
### 🐛 Bug Fixes
-### ⬇️ Dependency Updates
-- Update `pyqasm` requirement from >=0.4.0,<0.5.0 to >=0.4.0,<0.6.0 ([#236](https://github.com/qBraid/qbraid-qir/pull/236))
-- Update docutils requirement from <0.22 to <0.23 ([#238](https://github.com/qBraid/qbraid-qir/pull/238))
-- Bump actions/upload-pages-artifact from 3 to 4 ([#241](https://github.com/qBraid/qbraid-qir/pull/241))
-- Update pyqasm requirement from <0.6.0,>=0.4.0 to >=0.4.0,<1.1.0 ([#245](https://github.com/qBraid/qbraid-qir/pull/245))
-- Update qbraid requirement from <0.10.0,>=0.9.0 to >=0.9.0,<0.11.0 ([#247](https://github.com/qBraid/qbraid-qir/pull/247))
-- Bump actions/download-artifact from 5 to 6 ([#249](https://github.com/qBraid/qbraid-qir/pull/249))
-- Bump actions/upload-artifact from 4 to 5 ([#250](https://github.com/qBraid/qbraid-qir/pull/250))
-- Bump actions/checkout from v5 to v6 ([#254](https://github.com/qBraid/qbraid-qir/pull/254))
+- _(none this release)_
+
+### ⬇️ Dependency Updates
+- **pyqir**: Relax requirement from `>=0.10.0,<0.11.0` to `>=0.10.0,<0.13.0` so both 0.10.x and 0.12.x are supported. ([#265](https://github.com/qBraid/qbraid-qir/pull/265))
### 👋 Deprecations
+
+- _(none)_
+
+## Past releases
+
+Release notes for earlier versions are published on the [Releases](https://github.com/qBraid/qbraid-qir/releases) page.
\ No newline at end of file
diff --git a/CITATION.cff b/CITATION.cff
index 9a6e3863..fbb29f9a 100644
--- a/CITATION.cff
+++ b/CITATION.cff
@@ -19,6 +19,7 @@ keywords:
- llvm
- cirq
- openasm
+- squin
license: Apache-2.0
version: 0.5.0
date-released: '2025-12-15'
diff --git a/README.md b/README.md
index 319cf226..7ed44bd8 100644
--- a/README.md
+++ b/README.md
@@ -29,13 +29,13 @@
qBraid-SDK extension providing support for QIR conversions.
-[
](https://account.qbraid.com?gitHubUrl=https://github.com/qBraid/qbraid-qir.git)
+[
](https://account.qbraid.com/explore/projects/qbraid-qir-n792k0)
## Motivation
-This project aims to make [QIR](https://www.qir-alliance.org/) representations accessible via the qBraid-SDK [transpiler](#architecture-diagram), and by doing so, open the door to language-specific conversions from any and all high-level quantum languages [supported](https://docs.qbraid.com/sdk/user-guide/overview#supported-frontends) by `qbraid`. See QIR Alliance: [why do we need it?](https://www.qir-alliance.org/qir-book/concepts/why-do-we-need.html).
+This project aims to make [QIR](https://www.qir-alliance.org/) representations accessible via the qBraid-SDK [transpiler](#architecture-diagram), and by doing so, open the door to language-specific conversions from any and all high-level quantum languages [supported](https://docs.qbraid.com/v2/sdk/user-guide/overview#supported-frontends) by `qbraid`. See QIR Alliance: [why do we need it?](https://www.qir-alliance.org/qir-book/concepts/why-do-we-need.html).
## Installation
@@ -61,6 +61,12 @@ For Cirq to QIR conversions, install the `cirq` extra:
pip install 'qbraid-qir[cirq]'
```
+For QIR to SQUIN conversions, install the `squin` extra:
+
+```shell
+pip install 'qbraid-qir[squin]'
+```
+
### Install from source
You can also install from source by cloning this repository and running a pip install command
@@ -75,7 +81,7 @@ pip install .
To include optional dependencies when installing from source, use the same "extras_require" format, e.g.
```shell
-pip install '.[qasm3,cirq]'
+pip install '.[qasm3,cirq,squin]'
```
## Check version
@@ -90,7 +96,7 @@ qbraid_qir.__version__
## Resources
-- [User Guide](https://docs.qbraid.com/qir/user-guide)
+- [User Guide](https://docs.qbraid.com/v2/qir/user-guide)
- [API Reference](https://sdk.qbraid.com/qbraid-qir/api/qbraid_qir.html)
- [Example Notebooks](https://github.com/qBraid/qbraid-lab-demo/tree/main/qbraid_qir)
- [Docker Containers](docker)
@@ -140,9 +146,26 @@ module = cirq_to_qir(circuit, name="my-circuit")
ir = str(module)
```
+### SQUIN conversions
+
+```python
+from pyqir import BasicQisBuilder, SimpleModule
+from qbraid_qir.squin import load
+
+module = SimpleModule("ghz_n", num_qubits=2, num_results=2)
+qis = BasicQisBuilder(module.builder)
+
+qis.h(module.qubits[0])
+qis.cx(module.qubits[0], module.qubits[1])
+
+squin_module = load(module.ir())
+
+squin_module.print()
+```
+
## Architecture diagram
-qBraid-SDK transpiler hub-and-spokes [architecture](https://docs.qbraid.com/qir/user-guide/overview#architecture-diagram) with qbraid-qir integration (left) mapped to language specific conversion step in QIR abstraction [layers](https://www.qir-alliance.org/qir-book/concepts/why-do-we-need.html) (right).
+qBraid-SDK transpiler hub-and-spokes [architecture](https://docs.qbraid.com/v2/qir/user-guide/overview#architecture-diagram) with qbraid-qir integration (left) mapped to language specific conversion step in QIR abstraction [layers](https://www.qir-alliance.org/qir-book/concepts/why-do-we-need.html) (right).
@@ -169,10 +192,10 @@ citation details, please refer to [CITATION.cff](CITATION.cff).
@software{Gupta_qBraid-QIR_Python_package_2025,
author = {Gupta, Harshit and Hill, Ryan James},
license = {Apache-2.0},
- month = jun,
+ month = dec,
title = {{qBraid-QIR: Python package for QIR conversions, integrations, and utilities.}},
url = {https://github.com/qBraid/qbraid-qir},
- version = {0.4.0},
+ version = {0.5.0},
year = {2025}
}
```
diff --git a/bin/bump_version.py b/bin/bump_version.py
index 097c5eb7..7fbe0f9b 100755
--- a/bin/bump_version.py
+++ b/bin/bump_version.py
@@ -16,6 +16,7 @@
Script to bump the major, minor, or patch version in _version.py
"""
+
import pathlib
import sys
diff --git a/docs/api/qbraid_qir.squin.rst b/docs/api/qbraid_qir.squin.rst
new file mode 100644
index 00000000..9bcb604d
--- /dev/null
+++ b/docs/api/qbraid_qir.squin.rst
@@ -0,0 +1,8 @@
+:orphan:
+
+qbraid_qir.squin
+=================
+
+.. automodule:: qbraid_qir.squin
+ :undoc-members:
+ :show-inheritance:
\ No newline at end of file
diff --git a/docs/conf.py b/docs/conf.py
index b5c387f9..185680bd 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -15,7 +15,7 @@
# -- Project information -----------------------------------------------------
project = "qBraid"
-copyright = "2025, qBraid Development Team"
+copyright = "2026, qBraid Development Team"
author = "qBraid Development Team"
# The full version, including alpha/beta/rc tags
@@ -41,7 +41,7 @@
# set_type_checking_flag = True
autodoc_member_order = "bysource"
autoclass_content = "both"
-autodoc_mock_imports = ["cirq", "openqasm3", "pyqasm", "numpy", "numpy.typing"]
+autodoc_mock_imports = ["cirq", "openqasm3", "pyqasm", "numpy", "numpy.typing", "kirin", "bloqade"]
napoleon_numpy_docstring = False
todo_include_todos = True
mathjax_path = "https://cdn.jsdelivr.net/npm/mathjax@2/MathJax.js?config=TeX-AMS-MML_HTMLorMML"
diff --git a/docs/index.rst b/docs/index.rst
index e3c78ff1..977cd951 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -91,7 +91,7 @@ To enable specific conversions such as OpenQASM 3 to QIR or Cirq to QIR, you can
Resources
----------
-- `User Guide `_
+- `User Guide `_
- `Example Notebooks `_
- `API Reference `_
- `Source Code `_
@@ -117,6 +117,7 @@ Resources
api/qbraid_qir
api/qbraid_qir.cirq
api/qbraid_qir.qasm3
+ api/qbraid_qir.squin
.. toctree::
:caption: CORE API Reference
@@ -130,3 +131,9 @@ Resources
:hidden:
pyqasm
+
+.. toctree::
+ :caption: ALGOS API Reference
+ :hidden:
+
+ qbraid_algorithms
diff --git a/examples b/examples
index c0c58c9c..a38f897e 160000
--- a/examples
+++ b/examples
@@ -1 +1 @@
-Subproject commit c0c58c9cb8ddaf2a0f31253cb95d42e21fb7fd28
+Subproject commit a38f897eb5a6e917ee227ffb3afac8f1406021f6
diff --git a/pyproject.toml b/pyproject.toml
index 71136e61..68e0a876 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -9,7 +9,7 @@ description = "qBraid-SDK extension providing support for QIR conversions."
readme = "README.md"
authors = [{name = "qBraid Development Team"}, {email = "contact@qbraid.com"}]
license = "Apache-2.0"
-keywords = ["qbraid", "quantum", "qir", "llvm", "cirq", "openqasm"]
+keywords = ["qbraid", "quantum", "qir", "llvm", "cirq", "openqasm", "squin"]
classifiers = [
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
@@ -21,17 +21,18 @@ classifiers = [
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
+ "Programming Language :: Python :: 3.14",
"Programming Language :: Python :: 3 :: Only",
"Typing :: Typed",
"Topic :: Scientific/Engineering",
"Topic :: Scientific/Engineering :: Physics"
]
-dependencies = ["pyqir>=0.10.0,<0.11.0"]
+dependencies = ["pyqir>=0.10.0,<0.13.0"]
requires-python = ">=3.10"
[project.urls]
Homepage = "https://github.com/qBraid/qbraid-qir"
-Documentation = "https://docs.qbraid.com/qir"
+Documentation = "https://docs.qbraid.com/v2/qir"
"Bug Tracker" = "https://github.com/qBraid/qbraid-qir/issues"
Discord = "https://discord.gg/TPBU2sa8Et"
"Launch on Lab" = "https://account.qbraid.com/?gitHubUrl=https://github.com/qBraid/qbraid-qir.git"
@@ -40,7 +41,6 @@ Discord = "https://discord.gg/TPBU2sa8Et"
cirq = ["cirq-core>=1.3.0,<1.6.0"]
qasm3 = ["pyqasm>=0.4.0,<1.1.0", "numpy"]
squin = ["kirin-toolchain>=0.17.33", "bloqade-circuit>=0.9.1"]
-test = ["qbraid>=0.9.0,<0.11.0", "pytest", "pytest-cov", "autoqasm>=0.1.0", "cudaq"]
[tool.setuptools]
packages = ["qbraid_qir", "qbraid_qir.cirq", "qbraid_qir.qasm3", "qbraid_qir.squin"]
diff --git a/qbraid_qir/__init__.py b/qbraid_qir/__init__.py
index 122c0fbe..31c670ad 100644
--- a/qbraid_qir/__init__.py
+++ b/qbraid_qir/__init__.py
@@ -36,6 +36,7 @@
QirConversionError
"""
+
import importlib
from typing import TYPE_CHECKING
diff --git a/qbraid_qir/_pyqir_compat.py b/qbraid_qir/_pyqir_compat.py
new file mode 100644
index 00000000..c2d4e600
--- /dev/null
+++ b/qbraid_qir/_pyqir_compat.py
@@ -0,0 +1,73 @@
+# Copyright 2026 qBraid
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+Compatibility layer for different pyqir versions.
+
+PyQIR 0.12+ uses opaque pointers (QIR 2.0) and removed qubit_id/result_id/qubit_type/result_type,
+replacing them with ptr_id and PointerType. This module provides a single API that works
+with both pyqir 0.10.x (typed pointers) and 0.12+ (opaque pointers).
+"""
+
+from typing import Any, Optional
+
+import pyqir
+
+
+def _uses_opaque_pointers() -> bool:
+ """True if this pyqir build uses opaque pointers (0.12+)."""
+ return getattr(pyqir, "ptr_id", None) is not None
+
+
+def pointer_id(value: Any) -> Optional[int]:
+ """
+ Extract a static pointer id from a value (qubit or result).
+
+ Uses ptr_id on pyqir 0.12+, or qubit_id/result_id on 0.10.x (for qubit/result constants).
+ """
+ if _uses_opaque_pointers():
+ return pyqir.ptr_id(value)
+ # 0.10.x: qubit_id for qubit constants, result_id for result constants
+ qubit_id_fn = getattr(pyqir, "qubit_id", None)
+ result_id_fn = getattr(pyqir, "result_id", None)
+ if qubit_id_fn is not None:
+ out = qubit_id_fn(value)
+ if out is not None:
+ return out
+ if result_id_fn is not None:
+ return result_id_fn(value)
+ return None
+
+
+def qubit_pointer_type(context: Any) -> Any:
+ """
+ Return the LLVM type for a qubit pointer in this pyqir version.
+
+ Uses PointerType(Type.void(context)) on 0.12+, or qubit_type(context) on 0.10.x.
+ """
+ if _uses_opaque_pointers():
+ return pyqir.PointerType(pyqir.Type.void(context))
+ qubit_type_fn = getattr(pyqir, "qubit_type", None)
+ if qubit_type_fn is not None:
+ return qubit_type_fn(context)
+ return pyqir.PointerType(pyqir.Type.void(context))
+
+
+def pyqir_uses_opaque_pointers() -> bool:
+ """
+ Return True if the installed pyqir uses opaque pointers (QIR 2.0 / pyqir 0.12+).
+
+ Useful in tests to choose expected IR format (ptr vs %Qubit* / i8*).
+ """
+ return _uses_opaque_pointers()
diff --git a/qbraid_qir/_version.py b/qbraid_qir/_version.py
index dba69d61..3221e239 100644
--- a/qbraid_qir/_version.py
+++ b/qbraid_qir/_version.py
@@ -18,4 +18,5 @@
Version number (major.minor.patch[-label])
"""
+
__version__ = "0.5.0"
diff --git a/qbraid_qir/cirq/__init__.py b/qbraid_qir/cirq/__init__.py
index 0028c613..fd8a9250 100644
--- a/qbraid_qir/cirq/__init__.py
+++ b/qbraid_qir/cirq/__init__.py
@@ -44,6 +44,7 @@
CirqConversionError
"""
+
from .convert import cirq_to_qir
from .elements import CirqModule
from .exceptions import CirqConversionError
diff --git a/qbraid_qir/cirq/convert.py b/qbraid_qir/cirq/convert.py
index e19824b9..9362d350 100644
--- a/qbraid_qir/cirq/convert.py
+++ b/qbraid_qir/cirq/convert.py
@@ -16,6 +16,7 @@
Module containing Cirq to qBraid QIR conversion functions
"""
+
from typing import Optional
import cirq
diff --git a/qbraid_qir/cirq/exceptions.py b/qbraid_qir/cirq/exceptions.py
index bd319657..6249240b 100644
--- a/qbraid_qir/cirq/exceptions.py
+++ b/qbraid_qir/cirq/exceptions.py
@@ -16,6 +16,7 @@
Module defining exceptions for errors raised during Cirq conversions.
"""
+
from qbraid_qir.exceptions import QirConversionError
diff --git a/qbraid_qir/cirq/opsets.py b/qbraid_qir/cirq/opsets.py
index 0cb69458..de79301e 100644
--- a/qbraid_qir/cirq/opsets.py
+++ b/qbraid_qir/cirq/opsets.py
@@ -16,6 +16,7 @@
Module mapping supported Cirq gates/operations to pyqir functions.
"""
+
from typing import Callable
import cirq
diff --git a/qbraid_qir/cirq/visitor.py b/qbraid_qir/cirq/visitor.py
index 55d869aa..df6ef5de 100644
--- a/qbraid_qir/cirq/visitor.py
+++ b/qbraid_qir/cirq/visitor.py
@@ -16,6 +16,7 @@
Module defining CirqVisitor.
"""
+
import logging
from abc import ABCMeta, abstractmethod
@@ -25,6 +26,8 @@
import pyqir.rt
from pyqir import BasicBlock, Builder, Constant, IntType, PointerType
+from qbraid_qir._pyqir_compat import pointer_id
+
from .elements import CirqModule
from .opsets import map_cirq_op_to_pyqir_callable
@@ -110,7 +113,7 @@ def visit_operation(self, operation: cirq.Operation) -> None:
def handle_measurement(pyqir_func):
logger.debug("Visiting measurement operation '%s'", str(operation))
for qubit, result in zip(qubits, results):
- self._measured_qubits[pyqir.qubit_id(qubit)] = True
+ self._measured_qubits[pointer_id(qubit)] = True
pyqir_func(self._builder, qubit, result)
# dealing with conditional gates
diff --git a/qbraid_qir/profiles/core.py b/qbraid_qir/profiles/core.py
index f8c1aa2a..323f8ca3 100644
--- a/qbraid_qir/profiles/core.py
+++ b/qbraid_qir/profiles/core.py
@@ -16,6 +16,7 @@
Module containing core profile classes for QIR generation.
"""
+
from abc import ABC, abstractmethod
from dataclasses import dataclass
from typing import Callable
diff --git a/qbraid_qir/qasm3/__init__.py b/qbraid_qir/qasm3/__init__.py
index 99c8bcca..a525d8ca 100644
--- a/qbraid_qir/qasm3/__init__.py
+++ b/qbraid_qir/qasm3/__init__.py
@@ -43,6 +43,7 @@
Qasm3ConversionError
"""
+
from .convert import qasm3_to_qir
from .elements import QasmQIRModule
from .exceptions import Qasm3ConversionError
diff --git a/qbraid_qir/qasm3/convert.py b/qbraid_qir/qasm3/convert.py
index c1053c8b..d7b59e55 100644
--- a/qbraid_qir/qasm3/convert.py
+++ b/qbraid_qir/qasm3/convert.py
@@ -16,6 +16,7 @@
Module containing OpenQASM to QIR conversion functions
"""
+
from enum import Enum
from typing import Optional, Union
diff --git a/qbraid_qir/qasm3/elements.py b/qbraid_qir/qasm3/elements.py
index 87f0a34c..9ad34be1 100644
--- a/qbraid_qir/qasm3/elements.py
+++ b/qbraid_qir/qasm3/elements.py
@@ -18,6 +18,7 @@
Module defining Qasm3 Converter elements.
"""
+
from __future__ import annotations
import uuid
diff --git a/qbraid_qir/qasm3/exceptions.py b/qbraid_qir/qasm3/exceptions.py
index 0205de37..c544337e 100644
--- a/qbraid_qir/qasm3/exceptions.py
+++ b/qbraid_qir/qasm3/exceptions.py
@@ -16,6 +16,7 @@
Module defining exceptions for errors raised during QASM3 conversions.
"""
+
import logging
from typing import Optional, Type
diff --git a/qbraid_qir/qasm3/maps.py b/qbraid_qir/qasm3/maps.py
index 2b9188a9..09eaf3ea 100644
--- a/qbraid_qir/qasm3/maps.py
+++ b/qbraid_qir/qasm3/maps.py
@@ -15,6 +15,7 @@
"""
Module mapping supported QASM gates/operations to pyqir functions.
"""
+
from typing import Callable
import pyqir
diff --git a/qbraid_qir/qasm3/visitor.py b/qbraid_qir/qasm3/visitor.py
index c5420f53..65c333c6 100644
--- a/qbraid_qir/qasm3/visitor.py
+++ b/qbraid_qir/qasm3/visitor.py
@@ -21,6 +21,7 @@
without code duplication, based on JSON profile specifications.
"""
+
import logging
from typing import Any, Callable, List, Optional, Union
@@ -30,6 +31,7 @@
from openqasm3.ast import UnaryOperator
from pyqir import qis
+from qbraid_qir._pyqir_compat import pointer_id, qubit_pointer_type
from qbraid_qir.profiles import Profile, ProfileRegistry
from qbraid_qir.visitor import QIRVisitor
@@ -254,7 +256,7 @@ def _check_qubit_use_after_measurement(self, qubit_ids: List[pyqir.Constant]) ->
if not self._profile.allow_qubit_use_after_measurement():
# For profiles that don't allow it, we could add validation here
for qubit_id in qubit_ids:
- qubit_id_result = pyqir.qubit_id(qubit_id)
+ qubit_id_result = pointer_id(qubit_id)
if qubit_id_result is not None and self._measured_qubits.get(
qubit_id_result, False
):
@@ -283,7 +285,7 @@ def _visit_measurement(self, statement: qasm3_ast.QuantumMeasurementStatement) -
for src_id, tgt_id in zip(source_ids, target_ids):
# Track measurement if profile supports it
if self._profile.should_track_qubit_measurement():
- qubit_id_result = pyqir.qubit_id(src_id)
+ qubit_id_result = pointer_id(src_id)
if qubit_id_result is not None:
self._measured_qubits[qubit_id_result] = True
@@ -305,7 +307,7 @@ def _visit_reset(self, statement: qasm3_ast.QuantumReset) -> None:
for qid in qubit_ids:
# Clear measurement tracking if profile supports it
if self._profile.should_track_qubit_measurement():
- qubit_id_result = pyqir.qubit_id(qid)
+ qubit_id_result = pointer_id(qid)
if qubit_id_result is not None:
self._measured_qubits[qubit_id_result] = False
@@ -519,7 +521,7 @@ def _visit_external_gate_operation(self, operation: qasm3_ast.QuantumGate) -> No
if qir_function is None:
# First time seeing this external gate -> define new function
qir_function_arguments = [pyqir.Type.double(context)] * len(operation.arguments)
- qir_function_arguments += [pyqir.qubit_type(context)] * op_qubit_count
+ qir_function_arguments += [qubit_pointer_type(context)] * op_qubit_count
qir_function = pyqir.Function(
pyqir.FunctionType(pyqir.Type.void(context), qir_function_arguments),
diff --git a/qbraid_qir/serialization.py b/qbraid_qir/serialization.py
index 67a0eb80..54e3d8af 100644
--- a/qbraid_qir/serialization.py
+++ b/qbraid_qir/serialization.py
@@ -16,6 +16,7 @@
Module for exporting QIR to bitcode and LLVM IR files.
"""
+
from __future__ import annotations
import logging
diff --git a/qbraid_qir/squin/__init__.py b/qbraid_qir/squin/__init__.py
index 80bc4aae..148d6213 100644
--- a/qbraid_qir/squin/__init__.py
+++ b/qbraid_qir/squin/__init__.py
@@ -17,6 +17,7 @@
"""
This module contains the functionality to convert a PyQIR module into a squin kernel.
"""
+
from .visitor import load
__all__ = ["load"]
diff --git a/qbraid_qir/squin/maps.py b/qbraid_qir/squin/maps.py
index 681bff49..607e173d 100644
--- a/qbraid_qir/squin/maps.py
+++ b/qbraid_qir/squin/maps.py
@@ -15,6 +15,7 @@
"""
Module mapping PyQIR gate strings to squin gates.
"""
+
from bloqade import squin
# Mapping from full PyQIR gate strings to squin gates
diff --git a/qbraid_qir/squin/visitor.py b/qbraid_qir/squin/visitor.py
index bd3748bd..646e7524 100644
--- a/qbraid_qir/squin/visitor.py
+++ b/qbraid_qir/squin/visitor.py
@@ -15,6 +15,7 @@
"""
This module contains the functionality to convert a PyQIR module into a squin kernel.
"""
+
from __future__ import annotations
import os
@@ -28,6 +29,8 @@
from kirin.dialects import func, ilist, py
from kirin.rewrite import CFGCompactify, Walk
+from qbraid_qir._pyqir_compat import pointer_id
+
from .exceptions import InvalidSquinInput
from .maps import PYQIR_TO_SQUIN_GATES_MAP, QIR_TO_SQUIN_UNSUPPORTED_STATEMENTS_MAP
@@ -428,7 +431,7 @@ def visit_constant(
Returns:
ir.SSAValue: The SSA value of the constant.
"""
- qubit_id = pyqir.qubit_id(value)
+ qubit_id = pointer_id(value)
if qubit_id is not None and qubit_id in self.qubit_ssa_map:
return self.qubit_ssa_map[qubit_id]
diff --git a/requirements-test.txt b/requirements-test.txt
new file mode 100644
index 00000000..ca205973
--- /dev/null
+++ b/requirements-test.txt
@@ -0,0 +1,5 @@
+qbraid>=0.11.0,<0.12.0
+pytest
+pytest-cov
+autoqasm>=0.1.0
+cudaq; platform_system == "Linux" and python_version < '3.14'
\ No newline at end of file
diff --git a/tests/cirq_qir/conftest.py b/tests/cirq_qir/conftest.py
index 07565704..820e6222 100644
--- a/tests/cirq_qir/conftest.py
+++ b/tests/cirq_qir/conftest.py
@@ -17,6 +17,7 @@
without needing to import them (pytest will automatically discover them).
"""
+
# pylint: disable=unused-import,wildcard-import,unused-wildcard-import
from .fixtures.basic_gates import *
diff --git a/tests/cirq_qir/fixtures/basic_gates.py b/tests/cirq_qir/fixtures/basic_gates.py
index 2b860e00..d71f09ec 100644
--- a/tests/cirq_qir/fixtures/basic_gates.py
+++ b/tests/cirq_qir/fixtures/basic_gates.py
@@ -16,6 +16,7 @@
Module defining Cirq basic gate fixtures for use in tests.
"""
+
import cirq
import pytest
diff --git a/tests/cirq_qir/fixtures/cirq_circuits.py b/tests/cirq_qir/fixtures/cirq_circuits.py
index 1d36893f..a2b6799e 100644
--- a/tests/cirq_qir/fixtures/cirq_circuits.py
+++ b/tests/cirq_qir/fixtures/cirq_circuits.py
@@ -16,6 +16,7 @@
Module containing Cirq circuit fixtures for unit tests.
"""
+
import cirq
import pytest
diff --git a/tests/cirq_qir/fixtures/pyqir_circuits.py b/tests/cirq_qir/fixtures/pyqir_circuits.py
index 01f5e887..cd6fb4d0 100644
--- a/tests/cirq_qir/fixtures/pyqir_circuits.py
+++ b/tests/cirq_qir/fixtures/pyqir_circuits.py
@@ -16,6 +16,7 @@
Module containing PyQIR circuit fixtures for unit tests.
"""
+
import pytest
from pyqir import BasicQisBuilder, SimpleModule
diff --git a/tests/cirq_qir/resources/test_conditional_gates_opaque.ll b/tests/cirq_qir/resources/test_conditional_gates_opaque.ll
new file mode 100644
index 00000000..6aacc043
--- /dev/null
+++ b/tests/cirq_qir/resources/test_conditional_gates_opaque.ll
@@ -0,0 +1,89 @@
+; ModuleID = 'test_conditional_gates'
+source_filename = "circuit-778bcda"
+
+define void @main() #0 {
+entry:
+ call void @__quantum__rt__initialize(ptr null)
+ call void @__quantum__qis__h__body(ptr null)
+ call void @__quantum__qis__h__body(ptr inttoptr (i64 1 to ptr))
+ %0 = call i1 @__quantum__qis__read_result__body(ptr inttoptr (i64 1 to ptr))
+ br i1 %0, label %then, label %else
+
+then: ; preds = %entry
+ call void @__quantum__qis__z__body(ptr inttoptr (i64 2 to ptr))
+ br label %continue
+
+else: ; preds = %entry
+ call void @__quantum__qis__x__body(ptr inttoptr (i64 2 to ptr))
+ call void @__quantum__qis__x__body(ptr inttoptr (i64 2 to ptr))
+ br label %continue
+
+continue: ; preds = %else, %then
+ %1 = call i1 @__quantum__qis__read_result__body(ptr null)
+ br i1 %1, label %then1, label %else2
+
+then1: ; preds = %continue
+ call void @__quantum__qis__z__body(ptr inttoptr (i64 2 to ptr))
+ br label %continue3
+
+else2: ; preds = %continue
+ br label %continue3
+
+continue3: ; preds = %else2, %then1
+ call void @__quantum__qis__mz__body(ptr null, ptr null)
+ call void @__quantum__qis__mz__body(ptr inttoptr (i64 1 to ptr), ptr inttoptr (i64 1 to ptr))
+ %2 = call i1 @__quantum__qis__read_result__body(ptr inttoptr (i64 1 to ptr))
+ br i1 %2, label %then4, label %else5
+
+then4: ; preds = %continue3
+ call void @__quantum__qis__rz__body(double 5.000000e-01, ptr inttoptr (i64 2 to ptr))
+ br label %continue6
+
+else5: ; preds = %continue3
+ call void @__quantum__qis__x__body(ptr inttoptr (i64 2 to ptr))
+ call void @__quantum__qis__x__body(ptr inttoptr (i64 2 to ptr))
+ br label %continue6
+
+continue6: ; preds = %else5, %then4
+ %3 = call i1 @__quantum__qis__read_result__body(ptr null)
+ br i1 %3, label %then7, label %else8
+
+then7: ; preds = %continue6
+ call void @__quantum__qis__rz__body(double 5.000000e-01, ptr inttoptr (i64 2 to ptr))
+ br label %continue9
+
+else8: ; preds = %continue6
+ br label %continue9
+
+continue9: ; preds = %else8, %then7
+ call void @__quantum__rt__result_record_output(ptr null, ptr null)
+ call void @__quantum__rt__result_record_output(ptr inttoptr (i64 1 to ptr), ptr null)
+ call void @__quantum__rt__result_record_output(ptr inttoptr (i64 2 to ptr), ptr null)
+ ret void
+}
+
+declare void @__quantum__rt__initialize(ptr)
+
+declare void @__quantum__qis__h__body(ptr)
+
+declare i1 @__quantum__qis__read_result__body(ptr)
+
+declare void @__quantum__qis__z__body(ptr)
+
+declare void @__quantum__qis__x__body(ptr)
+
+declare void @__quantum__qis__mz__body(ptr, ptr writeonly) #1
+
+declare void @__quantum__qis__rz__body(double, ptr)
+
+declare void @__quantum__rt__result_record_output(ptr, ptr)
+
+attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="custom" "required_num_qubits"="3" "required_num_results"="3" }
+attributes #1 = { "irreversible" }
+
+!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}
diff --git a/tests/cirq_qir/resources/test_conditional_gates.ll b/tests/cirq_qir/resources/test_conditional_gates_typed.ll
similarity index 100%
rename from tests/cirq_qir/resources/test_conditional_gates.ll
rename to tests/cirq_qir/resources/test_conditional_gates_typed.ll
diff --git a/tests/cirq_qir/resources/test_qir_bell_cirq_opaque.ll b/tests/cirq_qir/resources/test_qir_bell_cirq_opaque.ll
new file mode 100644
index 00000000..422b18b6
--- /dev/null
+++ b/tests/cirq_qir/resources/test_qir_bell_cirq_opaque.ll
@@ -0,0 +1,27 @@
+; ModuleID = 'test_qir_bell'
+source_filename = "test_qir_bell"
+
+define void @main() #0 {
+entry:
+ call void @__quantum__qis__h__body(ptr null)
+ call void @__quantum__qis__cnot__body(ptr null, ptr inttoptr (i64 1 to ptr))
+ call void @__quantum__qis__mz__body(ptr null, ptr null)
+ call void @__quantum__qis__mz__body(ptr inttoptr (i64 1 to ptr), ptr inttoptr (i64 1 to ptr))
+ ret void
+}
+
+declare void @__quantum__qis__h__body(ptr)
+
+declare void @__quantum__qis__cnot__body(ptr, ptr)
+
+declare void @__quantum__qis__mz__body(ptr, ptr writeonly) #1
+
+attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="custom" "required_num_qubits"="2" "required_num_results"="2" }
+attributes #1 = { "irreversible" }
+
+!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}
diff --git a/tests/cirq_qir/resources/test_qir_bell.ll b/tests/cirq_qir/resources/test_qir_bell_cirq_typed.ll
similarity index 94%
rename from tests/cirq_qir/resources/test_qir_bell.ll
rename to tests/cirq_qir/resources/test_qir_bell_cirq_typed.ll
index befbc736..894818ff 100644
--- a/tests/cirq_qir/resources/test_qir_bell.ll
+++ b/tests/cirq_qir/resources/test_qir_bell_cirq_typed.ll
@@ -27,4 +27,4 @@ attributes #1 = { "irreversible" }
!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}
\ No newline at end of file
+!3 = !{i32 1, !"dynamic_result_management", i1 false}
diff --git a/tests/cirq_qir/resources/test_qir_bell_opaque.ll b/tests/cirq_qir/resources/test_qir_bell_opaque.ll
new file mode 100644
index 00000000..5dd8174f
--- /dev/null
+++ b/tests/cirq_qir/resources/test_qir_bell_opaque.ll
@@ -0,0 +1,27 @@
+; ModuleID = 'test_qir_bell'
+source_filename = "test_qir_bell"
+
+define void @main() #0 {
+entry:
+ call void @__quantum__qis__h__body(ptr null)
+ call void @__quantum__qis__cnot__body(ptr null, ptr inttoptr (i64 1 to ptr))
+ call void @__quantum__qis__mz__body(ptr null, ptr null)
+ call void @__quantum__qis__mz__body(ptr inttoptr (i64 1 to ptr), ptr inttoptr (i64 1 to ptr))
+ ret void
+}
+
+declare void @__quantum__qis__h__body(ptr)
+
+declare void @__quantum__qis__cnot__body(ptr, ptr)
+
+declare void @__quantum__qis__mz__body(ptr, ptr writeonly) #1
+
+attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="custom" "required_num_qubits"="2" "required_num_results"="2" }
+attributes #1 = { "irreversible" }
+
+!llvm.module.flags = !{!0, !1, !2, !3}
+
+!0 = !{i32 1, !"qir_major_version", i32 2}
+!1 = !{i32 7, !"qir_minor_version", i32 0}
+!2 = !{i32 1, !"dynamic_qubit_management", i1 false}
+!3 = !{i32 1, !"dynamic_result_management", i1 false}
diff --git a/tests/cirq_qir/resources/test_qir_bell_typed.ll b/tests/cirq_qir/resources/test_qir_bell_typed.ll
new file mode 100644
index 00000000..894818ff
--- /dev/null
+++ b/tests/cirq_qir/resources/test_qir_bell_typed.ll
@@ -0,0 +1,30 @@
+; ModuleID = 'test_qir_bell'
+source_filename = "test_qir_bell"
+
+%Qubit = type opaque
+%Result = 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*))
+ call void @__quantum__qis__mz__body(%Qubit* null, %Result* null)
+ call void @__quantum__qis__mz__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 1 to %Result*))
+ ret void
+}
+
+declare void @__quantum__qis__h__body(%Qubit*)
+
+declare void @__quantum__qis__cnot__body(%Qubit*, %Qubit*)
+
+declare void @__quantum__qis__mz__body(%Qubit*, %Result* writeonly) #1
+
+attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="custom" "required_num_qubits"="2" "required_num_results"="2" }
+attributes #1 = { "irreversible" }
+
+!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}
diff --git a/tests/cirq_qir/test_cirq_module.py b/tests/cirq_qir/test_cirq_module.py
index f99d830c..644f6436 100644
--- a/tests/cirq_qir/test_cirq_module.py
+++ b/tests/cirq_qir/test_cirq_module.py
@@ -16,6 +16,7 @@
Module containing unit tests for CirqModule and Module elements.
"""
+
import hashlib
import cirq
diff --git a/tests/cirq_qir/test_cirq_preprocess.py b/tests/cirq_qir/test_cirq_preprocess.py
index 75aaade5..07a3e38c 100644
--- a/tests/cirq_qir/test_cirq_preprocess.py
+++ b/tests/cirq_qir/test_cirq_preprocess.py
@@ -16,6 +16,7 @@
Test functions that preprocess Cirq circuits before conversion to QIR.
"""
+
import cirq
import numpy as np
import pytest
diff --git a/tests/cirq_qir/test_cirq_to_qir.py b/tests/cirq_qir/test_cirq_to_qir.py
index 657fb9ba..7f8d4692 100644
--- a/tests/cirq_qir/test_cirq_to_qir.py
+++ b/tests/cirq_qir/test_cirq_to_qir.py
@@ -16,6 +16,7 @@
Module containing unit tests for Cirq to QIR conversion functions.
"""
+
import os
from pathlib import Path
@@ -23,6 +24,7 @@
import pyqir
import pytest
+from qbraid_qir._pyqir_compat import pyqir_uses_opaque_pointers
from qbraid_qir.cirq import cirq_to_qir
from tests.cirq_qir.fixtures.basic_gates import (
double_op_tests,
@@ -54,10 +56,16 @@ def resources_file(filename: str) -> str:
return os.path.join(RESOURCES_DIR, f"{filename}.ll")
+def version_specific_ll_path(base_name: str) -> str:
+ """Path to typed or opaque fixture based on installed pyqir version."""
+ suffix = "opaque" if pyqir_uses_opaque_pointers() else "typed"
+ return os.path.join(RESOURCES_DIR, f"{base_name}_{suffix}.ll")
+
+
def compare_reference_ir(generated_bitcode: bytes, name: str) -> None:
module = pyqir.Module.from_bitcode(pyqir.Context(), generated_bitcode, f"{name}")
ir = str(module)
- file = os.path.join(os.path.dirname(__file__), f"resources/{name}.ll")
+ file = version_specific_ll_path(name)
expected = Path(file).read_text(encoding="utf-8")
assert ir == expected
@@ -195,8 +203,7 @@ def test_pauli_term_measurements():
def test_verify_qir_bell_fixture(pyqir_bell):
"""Test that pyqir fixture generates code equal to test_qir_bell.ll file."""
- test_name = "test_qir_bell"
- filepath = resources_file(test_name)
+ filepath = version_specific_ll_path("test_qir_bell")
assert_equal_qir(pyqir_bell.ir(), filepath)
@@ -210,7 +217,7 @@ def test_entry_point_name(cirq_bell):
def test_convert_bell_compare_file(cirq_bell):
"""Test converting Cirq bell circuit to QIR."""
test_name = "test_qir_bell"
- filepath = resources_file(test_name)
+ filepath = version_specific_ll_path("test_qir_bell_cirq")
module = cirq_to_qir(cirq_bell, name=test_name, initialize_runtime=False, record_output=False)
assert_equal_qir(str(module), filepath)
diff --git a/tests/cirq_qir/test_serialization.py b/tests/cirq_qir/test_serialization.py
index 69bba3d5..a632acf8 100644
--- a/tests/cirq_qir/test_serialization.py
+++ b/tests/cirq_qir/test_serialization.py
@@ -16,6 +16,7 @@
Unit tests for the export module
"""
+
import os
import pathlib
import shutil
diff --git a/tests/qasm3_qir/autoqasm/test_convert.py b/tests/qasm3_qir/autoqasm/test_convert.py
index aca5e08c..45e441f8 100644
--- a/tests/qasm3_qir/autoqasm/test_convert.py
+++ b/tests/qasm3_qir/autoqasm/test_convert.py
@@ -16,17 +16,25 @@
Tests the convert module of autoqasm to qir
"""
+
import re
from typing import TYPE_CHECKING
-import autoqasm as aq
-import autoqasm.instructions as ins
-import numpy as np
import pytest
-from pyqir import Module
-from qbraid.passes.qasm.compat import add_stdgates_include, insert_gate_def
-from qbraid_qir.qasm3 import qasm3_to_qir
+pytest.importorskip("autoqasm")
+
+# Imports after importorskip so optional dependency is not required at import time.
+import autoqasm as aq # pylint: disable=wrong-import-position
+import autoqasm.instructions as ins # pylint: disable=wrong-import-position
+import numpy as np # pylint: disable=wrong-import-position
+from pyqir import Module # pylint: disable=wrong-import-position
+from qbraid.passes.qasm.compat import ( # pylint: disable=wrong-import-position
+ add_stdgates_include,
+ insert_gate_def,
+)
+
+from qbraid_qir.qasm3 import qasm3_to_qir # pylint: disable=wrong-import-position
if TYPE_CHECKING:
from autoqasm.program import MainProgram
diff --git a/tests/qasm3_qir/conftest.py b/tests/qasm3_qir/conftest.py
index ccb3b8fa..5be19f05 100644
--- a/tests/qasm3_qir/conftest.py
+++ b/tests/qasm3_qir/conftest.py
@@ -17,6 +17,7 @@
without needing to import them (pytest will automatically discover them).
"""
+
# pylint: disable=unused-import,wildcard-import,unused-wildcard-import
from .fixtures.gates import *
diff --git a/tests/qasm3_qir/converter/test_alias.py b/tests/qasm3_qir/converter/test_alias.py
index 33c167ff..cc174ead 100644
--- a/tests/qasm3_qir/converter/test_alias.py
+++ b/tests/qasm3_qir/converter/test_alias.py
@@ -28,7 +28,7 @@
check_two_qubit_gate_op,
)
-from .test_if import compare_reference_ir, resources_file
+from .test_if import compare_reference_ir, version_specific_ll_file
def test_alias():
@@ -152,7 +152,7 @@ def test_alias_in_scope_1():
generated_qir = str(result).splitlines()
check_attributes(generated_qir, 4, 4)
- simple_file = resources_file("simple_if.ll")
+ simple_file = version_specific_ll_file("simple_if")
compare_reference_ir(result.bitcode, simple_file)
@@ -187,5 +187,5 @@ def test_alias_in_scope_2():
generated_qir = str(result).splitlines()
check_attributes(generated_qir, 4, 4)
- simple_file = resources_file("simple_if.ll")
+ simple_file = version_specific_ll_file("simple_if")
compare_reference_ir(result.bitcode, simple_file)
diff --git a/tests/qasm3_qir/converter/test_barrier.py b/tests/qasm3_qir/converter/test_barrier.py
index 28ae8425..107ea9ff 100644
--- a/tests/qasm3_qir/converter/test_barrier.py
+++ b/tests/qasm3_qir/converter/test_barrier.py
@@ -16,6 +16,7 @@
Module containing unit tests for QASM3 to QIR conversion functions.
"""
+
import pytest
from qbraid_qir.qasm3 import qasm3_to_qir
diff --git a/tests/qasm3_qir/converter/test_gates.py b/tests/qasm3_qir/converter/test_gates.py
index fe893ea5..cfab5079 100644
--- a/tests/qasm3_qir/converter/test_gates.py
+++ b/tests/qasm3_qir/converter/test_gates.py
@@ -16,6 +16,7 @@
Module containing unit tests for QASM3 to QIR conversion functions.
"""
+
import pytest
from qbraid_qir.qasm3 import qasm3_to_qir
@@ -248,8 +249,7 @@ def test_inv_gate_modifier():
def test_nested_gate_modifiers():
- complex_qir = qasm3_to_qir(
- """
+ complex_qir = qasm3_to_qir("""
OPENQASM 3;
include "stdgates.inc";
qubit[2] q;
@@ -262,8 +262,7 @@ def test_nested_gate_modifiers():
}
pow(1) @ inv @ pow(2) @ custom q;
pow(-1) @ custom q;
- """
- )
+ """)
generated_qir = str(complex_qir).splitlines()
check_attributes(generated_qir, 2, 0)
check_single_qubit_gate_op(generated_qir, 2, [0, 0, 0], "y")
@@ -271,14 +270,12 @@ def test_nested_gate_modifiers():
def test_ctrl_modifiers():
- ctrl_modifiers = qasm3_to_qir(
- """
+ ctrl_modifiers = qasm3_to_qir("""
OPENQASM 3;
include "stdgates.inc";
qubit[2] q;
ctrl @ x q[0], q[1];
- """
- )
+ """)
generated_qir = str(ctrl_modifiers).splitlines()
check_attributes(generated_qir, 2, 0)
check_two_qubit_gate_op(generated_qir, 1, [[0, 1]], "cx")
diff --git a/tests/qasm3_qir/converter/test_if.py b/tests/qasm3_qir/converter/test_if.py
index b4469e36..4176d7f1 100644
--- a/tests/qasm3_qir/converter/test_if.py
+++ b/tests/qasm3_qir/converter/test_if.py
@@ -22,6 +22,7 @@
import pyqir
+from qbraid_qir._pyqir_compat import pyqir_uses_opaque_pointers
from qbraid_qir.qasm3 import qasm3_to_qir
from tests.qir_utils import check_attributes, get_entry_point_body
@@ -34,6 +35,12 @@ def resources_file(filename: str) -> str:
return str(os.path.join(RESOURCES_DIR, f"{filename}"))
+def version_specific_ll_file(base: str) -> str:
+ """Path to typed or opaque .ll fixture based on installed pyqir version."""
+ suffix = "opaque" if pyqir_uses_opaque_pointers() else "typed"
+ return resources_file(f"{base}_{suffix}.ll")
+
+
def compare_reference_ir(generated_bitcode: bytes, file_path: str) -> None:
module = pyqir.Module.from_bitcode(pyqir.Context(), generated_bitcode, f"{file_path}")
ir = str(module)
@@ -74,7 +81,7 @@ def test_simple_if():
generated_qir = str(result).splitlines()
check_attributes(generated_qir, 4, 4)
- simple_file = resources_file("simple_if.ll")
+ simple_file = version_specific_ll_file("simple_if")
compare_reference_ir(result.bitcode, simple_file)
@@ -113,5 +120,5 @@ def test_complex_if():
generated_qir = str(result).splitlines()
check_attributes(generated_qir, 4, 8)
- complex_if = resources_file("complex_if.ll")
+ complex_if = version_specific_ll_file("complex_if")
compare_reference_ir(result.bitcode, complex_if)
diff --git a/tests/qasm3_qir/converter/test_loop.py b/tests/qasm3_qir/converter/test_loop.py
index 8c882518..ce8a2467 100644
--- a/tests/qasm3_qir/converter/test_loop.py
+++ b/tests/qasm3_qir/converter/test_loop.py
@@ -20,6 +20,7 @@
import pytest
+from qbraid_qir._pyqir_compat import pyqir_uses_opaque_pointers
from qbraid_qir.qasm3 import qasm3_to_qir
from tests.qir_utils import (
check_attributes,
@@ -47,6 +48,52 @@
EXAMPLE_QIR_OUTPUT = """; ModuleID = 'test'
source_filename = "test"
+define void @test() #0 {
+entry:
+ call void @__quantum__rt__initialize(ptr null)
+ call void @__quantum__qis__h__body(ptr null)
+ call void @__quantum__qis__h__body(ptr inttoptr (i64 1 to ptr))
+ call void @__quantum__qis__h__body(ptr inttoptr (i64 2 to ptr))
+ call void @__quantum__qis__h__body(ptr inttoptr (i64 3 to ptr))
+ call void @__quantum__qis__cnot__body(ptr null, ptr inttoptr (i64 1 to ptr))
+ call void @__quantum__qis__cnot__body(ptr inttoptr (i64 1 to ptr), ptr inttoptr (i64 2 to ptr))
+ call void @__quantum__qis__cnot__body(ptr inttoptr (i64 2 to ptr), ptr inttoptr (i64 3 to ptr))
+ call void @__quantum__qis__mz__body(ptr null, ptr null)
+ call void @__quantum__qis__mz__body(ptr inttoptr (i64 1 to ptr), ptr inttoptr (i64 1 to ptr))
+ call void @__quantum__qis__mz__body(ptr inttoptr (i64 2 to ptr), ptr inttoptr (i64 2 to ptr))
+ call void @__quantum__qis__mz__body(ptr inttoptr (i64 3 to ptr), ptr inttoptr (i64 3 to ptr))
+ call void @__quantum__rt__result_record_output(ptr null, ptr null)
+ call void @__quantum__rt__result_record_output(ptr inttoptr (i64 1 to ptr), ptr null)
+ call void @__quantum__rt__result_record_output(ptr inttoptr (i64 2 to ptr), ptr null)
+ call void @__quantum__rt__result_record_output(ptr inttoptr (i64 3 to ptr), ptr null)
+ ret void
+}
+
+declare void @__quantum__rt__initialize(ptr)
+
+declare void @__quantum__qis__h__body(ptr)
+
+declare void @__quantum__qis__cnot__body(ptr, ptr)
+
+declare void @__quantum__qis__mz__body(ptr, ptr writeonly) #1
+
+declare void @__quantum__rt__result_record_output(ptr, ptr)
+
+attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="base" "required_num_qubits"="4" "required_num_results"="4" }
+attributes #1 = { "irreversible" }
+
+!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}
+"""
+
+
+EXAMPLE_QIR_OUTPUT_TYPED = """; ModuleID = 'test'
+source_filename = "test"
+
%Qubit = type opaque
%Result = type opaque
@@ -93,6 +140,10 @@
"""
+def _example_qir_expected():
+ return EXAMPLE_QIR_OUTPUT if pyqir_uses_opaque_pointers() else EXAMPLE_QIR_OUTPUT_TYPED
+
+
def test_convert_qasm3_for_loop():
"""Test converting a QASM3 program that contains a for loop."""
qir_expected = qasm3_to_qir(EXAMPLE_WITHOUT_LOOP, name="test")
@@ -113,7 +164,7 @@ def test_convert_qasm3_for_loop():
name="test",
)
assert str(qir_expected) == str(qir_from_loop)
- assert str(qir_from_loop) == EXAMPLE_QIR_OUTPUT
+ assert str(qir_from_loop) == _example_qir_expected()
def test_convert_qasm3_for_loop_shadow():
@@ -276,7 +327,7 @@ def test_convert_qasm3_for_loop_discrete_set():
name="test",
)
assert str(qir_expected) == str(qir_from_loop)
- assert str(qir_from_loop) == EXAMPLE_QIR_OUTPUT
+ assert str(qir_from_loop) == _example_qir_expected()
def test_function_executed_in_loop():
diff --git a/tests/qasm3_qir/converter/test_switch.py b/tests/qasm3_qir/converter/test_switch.py
index 83278378..d7aa6dd8 100644
--- a/tests/qasm3_qir/converter/test_switch.py
+++ b/tests/qasm3_qir/converter/test_switch.py
@@ -18,7 +18,6 @@
"""
-
from qbraid_qir.qasm3 import qasm3_to_qir
from tests.qir_utils import (
check_attributes,
diff --git a/tests/qasm3_qir/fixtures/gates.py b/tests/qasm3_qir/fixtures/gates.py
index 4cfe1016..3183819f 100644
--- a/tests/qasm3_qir/fixtures/gates.py
+++ b/tests/qasm3_qir/fixtures/gates.py
@@ -16,6 +16,7 @@
Module defining Cirq basic gate fixtures for use in tests.
"""
+
import os
import pytest
diff --git a/tests/qasm3_qir/fixtures/resources/complex_if.ll b/tests/qasm3_qir/fixtures/resources/complex_if.ll
index 7930253e..26e6a544 100644
--- a/tests/qasm3_qir/fixtures/resources/complex_if.ll
+++ b/tests/qasm3_qir/fixtures/resources/complex_if.ll
@@ -1,42 +1,39 @@
; ModuleID = 'program-b7eef4a0-4573-11f0-be85-773714bb7840'
source_filename = "program-b7eef4a0-4573-11f0-be85-773714bb7840"
-%Qubit = type opaque
-%Result = type opaque
-
define void @main() #0 {
entry:
- call void @__quantum__rt__initialize(i8* null)
- call void @__quantum__qis__h__body(%Qubit* null)
- call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 1 to %Qubit*))
- call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 2 to %Qubit*))
- call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 3 to %Qubit*))
- call void @__quantum__qis__mz__body(%Qubit* null, %Result* inttoptr (i64 4 to %Result*))
- call void @__quantum__qis__mz__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 5 to %Result*))
- call void @__quantum__qis__mz__body(%Qubit* inttoptr (i64 2 to %Qubit*), %Result* inttoptr (i64 6 to %Result*))
- call void @__quantum__qis__mz__body(%Qubit* inttoptr (i64 3 to %Qubit*), %Result* inttoptr (i64 7 to %Result*))
- call void @__quantum__qis__reset__body(%Qubit* null)
- call void @__quantum__qis__reset__body(%Qubit* inttoptr (i64 1 to %Qubit*))
- call void @__quantum__qis__reset__body(%Qubit* inttoptr (i64 2 to %Qubit*))
- call void @__quantum__qis__reset__body(%Qubit* inttoptr (i64 3 to %Qubit*))
- %0 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 4 to %Result*))
+ call void @__quantum__rt__initialize(ptr null)
+ call void @__quantum__qis__h__body(ptr null)
+ call void @__quantum__qis__h__body(ptr inttoptr (i64 1 to ptr))
+ call void @__quantum__qis__h__body(ptr inttoptr (i64 2 to ptr))
+ call void @__quantum__qis__h__body(ptr inttoptr (i64 3 to ptr))
+ call void @__quantum__qis__mz__body(ptr null, ptr inttoptr (i64 4 to ptr))
+ call void @__quantum__qis__mz__body(ptr inttoptr (i64 1 to ptr), ptr inttoptr (i64 5 to ptr))
+ call void @__quantum__qis__mz__body(ptr inttoptr (i64 2 to ptr), ptr inttoptr (i64 6 to ptr))
+ call void @__quantum__qis__mz__body(ptr inttoptr (i64 3 to ptr), ptr inttoptr (i64 7 to ptr))
+ call void @__quantum__qis__reset__body(ptr null)
+ call void @__quantum__qis__reset__body(ptr inttoptr (i64 1 to ptr))
+ call void @__quantum__qis__reset__body(ptr inttoptr (i64 2 to ptr))
+ call void @__quantum__qis__reset__body(ptr inttoptr (i64 3 to ptr))
+ %0 = call i1 @__quantum__qis__read_result__body(ptr inttoptr (i64 4 to ptr))
br i1 %0, label %then, label %else
then: ; preds = %entry
- call void @__quantum__qis__x__body(%Qubit* null)
- call void @__quantum__qis__cnot__body(%Qubit* null, %Qubit* inttoptr (i64 1 to %Qubit*))
- %1 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 5 to %Result*))
+ call void @__quantum__qis__x__body(ptr null)
+ call void @__quantum__qis__cnot__body(ptr null, ptr inttoptr (i64 1 to ptr))
+ %1 = call i1 @__quantum__qis__read_result__body(ptr inttoptr (i64 5 to ptr))
br i1 %1, label %then1, label %else2
else: ; preds = %entry
br label %continue
continue: ; preds = %else, %continue3
- %2 = call i1 @__quantum__qis__read_result__body(%Result* null)
+ %2 = call i1 @__quantum__qis__read_result__body(ptr null)
br i1 %2, label %then4, label %else5
then1: ; preds = %then
- call void @__quantum__qis__cnot__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Qubit* inttoptr (i64 2 to %Qubit*))
+ call void @__quantum__qis__cnot__body(ptr inttoptr (i64 1 to ptr), ptr inttoptr (i64 2 to ptr))
br label %continue3
else2: ; preds = %then
@@ -46,43 +43,43 @@ continue3: ; preds = %else2, %then1
br label %continue
then4: ; preds = %continue
- call void @__quantum__qis__cnot__body(%Qubit* inttoptr (i64 2 to %Qubit*), %Qubit* inttoptr (i64 3 to %Qubit*))
- call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 2 to %Qubit*))
+ call void @__quantum__qis__cnot__body(ptr inttoptr (i64 2 to ptr), ptr inttoptr (i64 3 to ptr))
+ call void @__quantum__qis__h__body(ptr inttoptr (i64 2 to ptr))
br label %continue6
else5: ; preds = %continue
br label %continue6
continue6: ; preds = %else5, %then4
- call void @__quantum__rt__result_record_output(%Result* null, i8* null)
- call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 1 to %Result*), i8* null)
- call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 2 to %Result*), i8* null)
- call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 3 to %Result*), i8* null)
+ call void @__quantum__rt__result_record_output(ptr null, ptr null)
+ call void @__quantum__rt__result_record_output(ptr inttoptr (i64 1 to ptr), ptr null)
+ call void @__quantum__rt__result_record_output(ptr inttoptr (i64 2 to ptr), ptr null)
+ call void @__quantum__rt__result_record_output(ptr inttoptr (i64 3 to ptr), ptr null)
ret void
}
-declare void @__quantum__rt__initialize(i8*)
+declare void @__quantum__rt__initialize(ptr)
-declare void @__quantum__qis__h__body(%Qubit*)
+declare void @__quantum__qis__h__body(ptr)
-declare void @__quantum__qis__mz__body(%Qubit*, %Result* writeonly) #1
+declare void @__quantum__qis__mz__body(ptr, ptr writeonly) #1
-declare void @__quantum__qis__reset__body(%Qubit*)
+declare void @__quantum__qis__reset__body(ptr)
-declare i1 @__quantum__qis__read_result__body(%Result*)
+declare i1 @__quantum__qis__read_result__body(ptr)
-declare void @__quantum__qis__x__body(%Qubit*)
+declare void @__quantum__qis__x__body(ptr)
-declare void @__quantum__qis__cnot__body(%Qubit*, %Qubit*)
+declare void @__quantum__qis__cnot__body(ptr, ptr)
-declare void @__quantum__rt__result_record_output(%Result*, i8*)
+declare void @__quantum__rt__result_record_output(ptr, ptr)
attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="base" "required_num_qubits"="4" "required_num_results"="8" }
attributes #1 = { "irreversible" }
!llvm.module.flags = !{!0, !1, !2, !3}
-!0 = !{i32 1, !"qir_major_version", i32 1}
+!0 = !{i32 1, !"qir_major_version", i32 2}
!1 = !{i32 7, !"qir_minor_version", i32 0}
!2 = !{i32 1, !"dynamic_qubit_management", i1 false}
-!3 = !{i32 1, !"dynamic_result_management", i1 false}
\ No newline at end of file
+!3 = !{i32 1, !"dynamic_result_management", i1 false}
diff --git a/tests/qasm3_qir/fixtures/resources/complex_if_opaque.ll b/tests/qasm3_qir/fixtures/resources/complex_if_opaque.ll
new file mode 100644
index 00000000..26e6a544
--- /dev/null
+++ b/tests/qasm3_qir/fixtures/resources/complex_if_opaque.ll
@@ -0,0 +1,85 @@
+; ModuleID = 'program-b7eef4a0-4573-11f0-be85-773714bb7840'
+source_filename = "program-b7eef4a0-4573-11f0-be85-773714bb7840"
+
+define void @main() #0 {
+entry:
+ call void @__quantum__rt__initialize(ptr null)
+ call void @__quantum__qis__h__body(ptr null)
+ call void @__quantum__qis__h__body(ptr inttoptr (i64 1 to ptr))
+ call void @__quantum__qis__h__body(ptr inttoptr (i64 2 to ptr))
+ call void @__quantum__qis__h__body(ptr inttoptr (i64 3 to ptr))
+ call void @__quantum__qis__mz__body(ptr null, ptr inttoptr (i64 4 to ptr))
+ call void @__quantum__qis__mz__body(ptr inttoptr (i64 1 to ptr), ptr inttoptr (i64 5 to ptr))
+ call void @__quantum__qis__mz__body(ptr inttoptr (i64 2 to ptr), ptr inttoptr (i64 6 to ptr))
+ call void @__quantum__qis__mz__body(ptr inttoptr (i64 3 to ptr), ptr inttoptr (i64 7 to ptr))
+ call void @__quantum__qis__reset__body(ptr null)
+ call void @__quantum__qis__reset__body(ptr inttoptr (i64 1 to ptr))
+ call void @__quantum__qis__reset__body(ptr inttoptr (i64 2 to ptr))
+ call void @__quantum__qis__reset__body(ptr inttoptr (i64 3 to ptr))
+ %0 = call i1 @__quantum__qis__read_result__body(ptr inttoptr (i64 4 to ptr))
+ br i1 %0, label %then, label %else
+
+then: ; preds = %entry
+ call void @__quantum__qis__x__body(ptr null)
+ call void @__quantum__qis__cnot__body(ptr null, ptr inttoptr (i64 1 to ptr))
+ %1 = call i1 @__quantum__qis__read_result__body(ptr inttoptr (i64 5 to ptr))
+ br i1 %1, label %then1, label %else2
+
+else: ; preds = %entry
+ br label %continue
+
+continue: ; preds = %else, %continue3
+ %2 = call i1 @__quantum__qis__read_result__body(ptr null)
+ br i1 %2, label %then4, label %else5
+
+then1: ; preds = %then
+ call void @__quantum__qis__cnot__body(ptr inttoptr (i64 1 to ptr), ptr inttoptr (i64 2 to ptr))
+ br label %continue3
+
+else2: ; preds = %then
+ br label %continue3
+
+continue3: ; preds = %else2, %then1
+ br label %continue
+
+then4: ; preds = %continue
+ call void @__quantum__qis__cnot__body(ptr inttoptr (i64 2 to ptr), ptr inttoptr (i64 3 to ptr))
+ call void @__quantum__qis__h__body(ptr inttoptr (i64 2 to ptr))
+ br label %continue6
+
+else5: ; preds = %continue
+ br label %continue6
+
+continue6: ; preds = %else5, %then4
+ call void @__quantum__rt__result_record_output(ptr null, ptr null)
+ call void @__quantum__rt__result_record_output(ptr inttoptr (i64 1 to ptr), ptr null)
+ call void @__quantum__rt__result_record_output(ptr inttoptr (i64 2 to ptr), ptr null)
+ call void @__quantum__rt__result_record_output(ptr inttoptr (i64 3 to ptr), ptr null)
+ ret void
+}
+
+declare void @__quantum__rt__initialize(ptr)
+
+declare void @__quantum__qis__h__body(ptr)
+
+declare void @__quantum__qis__mz__body(ptr, ptr writeonly) #1
+
+declare void @__quantum__qis__reset__body(ptr)
+
+declare i1 @__quantum__qis__read_result__body(ptr)
+
+declare void @__quantum__qis__x__body(ptr)
+
+declare void @__quantum__qis__cnot__body(ptr, ptr)
+
+declare void @__quantum__rt__result_record_output(ptr, ptr)
+
+attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="base" "required_num_qubits"="4" "required_num_results"="8" }
+attributes #1 = { "irreversible" }
+
+!llvm.module.flags = !{!0, !1, !2, !3}
+
+!0 = !{i32 1, !"qir_major_version", i32 2}
+!1 = !{i32 7, !"qir_minor_version", i32 0}
+!2 = !{i32 1, !"dynamic_qubit_management", i1 false}
+!3 = !{i32 1, !"dynamic_result_management", i1 false}
diff --git a/tests/qasm3_qir/fixtures/resources/complex_if_typed.ll b/tests/qasm3_qir/fixtures/resources/complex_if_typed.ll
new file mode 100644
index 00000000..2c8ac57a
--- /dev/null
+++ b/tests/qasm3_qir/fixtures/resources/complex_if_typed.ll
@@ -0,0 +1,88 @@
+; ModuleID = 'program-b7eef4a0-4573-11f0-be85-773714bb7840'
+source_filename = "program-b7eef4a0-4573-11f0-be85-773714bb7840"
+
+%Qubit = type opaque
+%Result = type opaque
+
+define void @main() #0 {
+entry:
+ call void @__quantum__rt__initialize(i8* null)
+ call void @__quantum__qis__h__body(%Qubit* null)
+ call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 1 to %Qubit*))
+ call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 2 to %Qubit*))
+ call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 3 to %Qubit*))
+ call void @__quantum__qis__mz__body(%Qubit* null, %Result* inttoptr (i64 4 to %Result*))
+ call void @__quantum__qis__mz__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 5 to %Result*))
+ call void @__quantum__qis__mz__body(%Qubit* inttoptr (i64 2 to %Qubit*), %Result* inttoptr (i64 6 to %Result*))
+ call void @__quantum__qis__mz__body(%Qubit* inttoptr (i64 3 to %Qubit*), %Result* inttoptr (i64 7 to %Result*))
+ call void @__quantum__qis__reset__body(%Qubit* null)
+ call void @__quantum__qis__reset__body(%Qubit* inttoptr (i64 1 to %Qubit*))
+ call void @__quantum__qis__reset__body(%Qubit* inttoptr (i64 2 to %Qubit*))
+ call void @__quantum__qis__reset__body(%Qubit* inttoptr (i64 3 to %Qubit*))
+ %0 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 4 to %Result*))
+ br i1 %0, label %then, label %else
+
+then: ; preds = %entry
+ call void @__quantum__qis__x__body(%Qubit* null)
+ call void @__quantum__qis__cnot__body(%Qubit* null, %Qubit* inttoptr (i64 1 to %Qubit*))
+ %1 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 5 to %Result*))
+ br i1 %1, label %then1, label %else2
+
+else: ; preds = %entry
+ br label %continue
+
+continue: ; preds = %else, %continue3
+ %2 = call i1 @__quantum__qis__read_result__body(%Result* null)
+ br i1 %2, label %then4, label %else5
+
+then1: ; preds = %then
+ call void @__quantum__qis__cnot__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Qubit* inttoptr (i64 2 to %Qubit*))
+ br label %continue3
+
+else2: ; preds = %then
+ br label %continue3
+
+continue3: ; preds = %else2, %then1
+ br label %continue
+
+then4: ; preds = %continue
+ call void @__quantum__qis__cnot__body(%Qubit* inttoptr (i64 2 to %Qubit*), %Qubit* inttoptr (i64 3 to %Qubit*))
+ call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 2 to %Qubit*))
+ br label %continue6
+
+else5: ; preds = %continue
+ br label %continue6
+
+continue6: ; preds = %else5, %then4
+ call void @__quantum__rt__result_record_output(%Result* null, i8* null)
+ call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 1 to %Result*), i8* null)
+ call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 2 to %Result*), i8* null)
+ call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 3 to %Result*), i8* null)
+ ret void
+}
+
+declare void @__quantum__rt__initialize(i8*)
+
+declare void @__quantum__qis__h__body(%Qubit*)
+
+declare void @__quantum__qis__mz__body(%Qubit*, %Result* writeonly) #1
+
+declare void @__quantum__qis__reset__body(%Qubit*)
+
+declare i1 @__quantum__qis__read_result__body(%Result*)
+
+declare void @__quantum__qis__x__body(%Qubit*)
+
+declare void @__quantum__qis__cnot__body(%Qubit*, %Qubit*)
+
+declare void @__quantum__rt__result_record_output(%Result*, i8*)
+
+attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="base" "required_num_qubits"="4" "required_num_results"="8" }
+attributes #1 = { "irreversible" }
+
+!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}
diff --git a/tests/qasm3_qir/fixtures/resources/simple_if.ll b/tests/qasm3_qir/fixtures/resources/simple_if.ll
index 037359a5..ab90d3d9 100644
--- a/tests/qasm3_qir/fixtures/resources/simple_if.ll
+++ b/tests/qasm3_qir/fixtures/resources/simple_if.ll
@@ -1,86 +1,83 @@
; ModuleID = 'program-fe043bae-4572-11f0-be85-773714bb7840'
source_filename = "program-fe043bae-4572-11f0-be85-773714bb7840"
-%Qubit = type opaque
-%Result = type opaque
-
define void @main() #0 {
entry:
- call void @__quantum__rt__initialize(i8* null)
- call void @__quantum__qis__h__body(%Qubit* null)
- call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 1 to %Qubit*))
- call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 2 to %Qubit*))
- call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 3 to %Qubit*))
- call void @__quantum__qis__mz__body(%Qubit* null, %Result* null)
- call void @__quantum__qis__mz__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 1 to %Result*))
- call void @__quantum__qis__mz__body(%Qubit* inttoptr (i64 2 to %Qubit*), %Result* inttoptr (i64 2 to %Result*))
- call void @__quantum__qis__mz__body(%Qubit* inttoptr (i64 3 to %Qubit*), %Result* inttoptr (i64 3 to %Result*))
- call void @__quantum__qis__reset__body(%Qubit* null)
- call void @__quantum__qis__reset__body(%Qubit* inttoptr (i64 1 to %Qubit*))
- call void @__quantum__qis__reset__body(%Qubit* inttoptr (i64 2 to %Qubit*))
- %0 = call i1 @__quantum__qis__read_result__body(%Result* null)
+ call void @__quantum__rt__initialize(ptr null)
+ call void @__quantum__qis__h__body(ptr null)
+ call void @__quantum__qis__h__body(ptr inttoptr (i64 1 to ptr))
+ call void @__quantum__qis__h__body(ptr inttoptr (i64 2 to ptr))
+ call void @__quantum__qis__h__body(ptr inttoptr (i64 3 to ptr))
+ call void @__quantum__qis__mz__body(ptr null, ptr null)
+ call void @__quantum__qis__mz__body(ptr inttoptr (i64 1 to ptr), ptr inttoptr (i64 1 to ptr))
+ call void @__quantum__qis__mz__body(ptr inttoptr (i64 2 to ptr), ptr inttoptr (i64 2 to ptr))
+ call void @__quantum__qis__mz__body(ptr inttoptr (i64 3 to ptr), ptr inttoptr (i64 3 to ptr))
+ call void @__quantum__qis__reset__body(ptr null)
+ call void @__quantum__qis__reset__body(ptr inttoptr (i64 1 to ptr))
+ call void @__quantum__qis__reset__body(ptr inttoptr (i64 2 to ptr))
+ %0 = call i1 @__quantum__qis__read_result__body(ptr null)
br i1 %0, label %then, label %else
then: ; preds = %entry
- call void @__quantum__qis__x__body(%Qubit* null)
- call void @__quantum__qis__cnot__body(%Qubit* null, %Qubit* inttoptr (i64 1 to %Qubit*))
+ call void @__quantum__qis__x__body(ptr null)
+ call void @__quantum__qis__cnot__body(ptr null, ptr inttoptr (i64 1 to ptr))
br label %continue
else: ; preds = %entry
br label %continue
continue: ; preds = %else, %then
- %1 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 1 to %Result*))
+ %1 = call i1 @__quantum__qis__read_result__body(ptr inttoptr (i64 1 to ptr))
br i1 %1, label %then1, label %else2
then1: ; preds = %continue
- call void @__quantum__qis__cnot__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Qubit* inttoptr (i64 2 to %Qubit*))
+ call void @__quantum__qis__cnot__body(ptr inttoptr (i64 1 to ptr), ptr inttoptr (i64 2 to ptr))
br label %continue3
else2: ; preds = %continue
br label %continue3
continue3: ; preds = %else2, %then1
- %2 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 2 to %Result*))
+ %2 = call i1 @__quantum__qis__read_result__body(ptr inttoptr (i64 2 to ptr))
br i1 %2, label %then4, label %else5
then4: ; preds = %continue3
br label %continue6
else5: ; preds = %continue3
- call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 2 to %Qubit*))
+ call void @__quantum__qis__h__body(ptr inttoptr (i64 2 to ptr))
br label %continue6
continue6: ; preds = %else5, %then4
- call void @__quantum__rt__result_record_output(%Result* null, i8* null)
- call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 1 to %Result*), i8* null)
- call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 2 to %Result*), i8* null)
- call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 3 to %Result*), i8* null)
+ call void @__quantum__rt__result_record_output(ptr null, ptr null)
+ call void @__quantum__rt__result_record_output(ptr inttoptr (i64 1 to ptr), ptr null)
+ call void @__quantum__rt__result_record_output(ptr inttoptr (i64 2 to ptr), ptr null)
+ call void @__quantum__rt__result_record_output(ptr inttoptr (i64 3 to ptr), ptr null)
ret void
}
-declare void @__quantum__rt__initialize(i8*)
+declare void @__quantum__rt__initialize(ptr)
-declare void @__quantum__qis__h__body(%Qubit*)
+declare void @__quantum__qis__h__body(ptr)
-declare void @__quantum__qis__mz__body(%Qubit*, %Result* writeonly) #1
+declare void @__quantum__qis__mz__body(ptr, ptr writeonly) #1
-declare void @__quantum__qis__reset__body(%Qubit*)
+declare void @__quantum__qis__reset__body(ptr)
-declare i1 @__quantum__qis__read_result__body(%Result*)
+declare i1 @__quantum__qis__read_result__body(ptr)
-declare void @__quantum__qis__x__body(%Qubit*)
+declare void @__quantum__qis__x__body(ptr)
-declare void @__quantum__qis__cnot__body(%Qubit*, %Qubit*)
+declare void @__quantum__qis__cnot__body(ptr, ptr)
-declare void @__quantum__rt__result_record_output(%Result*, i8*)
+declare void @__quantum__rt__result_record_output(ptr, ptr)
attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="base" "required_num_qubits"="4" "required_num_results"="4" }
attributes #1 = { "irreversible" }
!llvm.module.flags = !{!0, !1, !2, !3}
-!0 = !{i32 1, !"qir_major_version", i32 1}
+!0 = !{i32 1, !"qir_major_version", i32 2}
!1 = !{i32 7, !"qir_minor_version", i32 0}
!2 = !{i32 1, !"dynamic_qubit_management", i1 false}
-!3 = !{i32 1, !"dynamic_result_management", i1 false}
\ No newline at end of file
+!3 = !{i32 1, !"dynamic_result_management", i1 false}
diff --git a/tests/qasm3_qir/fixtures/resources/simple_if_opaque.ll b/tests/qasm3_qir/fixtures/resources/simple_if_opaque.ll
new file mode 100644
index 00000000..ab90d3d9
--- /dev/null
+++ b/tests/qasm3_qir/fixtures/resources/simple_if_opaque.ll
@@ -0,0 +1,83 @@
+; ModuleID = 'program-fe043bae-4572-11f0-be85-773714bb7840'
+source_filename = "program-fe043bae-4572-11f0-be85-773714bb7840"
+
+define void @main() #0 {
+entry:
+ call void @__quantum__rt__initialize(ptr null)
+ call void @__quantum__qis__h__body(ptr null)
+ call void @__quantum__qis__h__body(ptr inttoptr (i64 1 to ptr))
+ call void @__quantum__qis__h__body(ptr inttoptr (i64 2 to ptr))
+ call void @__quantum__qis__h__body(ptr inttoptr (i64 3 to ptr))
+ call void @__quantum__qis__mz__body(ptr null, ptr null)
+ call void @__quantum__qis__mz__body(ptr inttoptr (i64 1 to ptr), ptr inttoptr (i64 1 to ptr))
+ call void @__quantum__qis__mz__body(ptr inttoptr (i64 2 to ptr), ptr inttoptr (i64 2 to ptr))
+ call void @__quantum__qis__mz__body(ptr inttoptr (i64 3 to ptr), ptr inttoptr (i64 3 to ptr))
+ call void @__quantum__qis__reset__body(ptr null)
+ call void @__quantum__qis__reset__body(ptr inttoptr (i64 1 to ptr))
+ call void @__quantum__qis__reset__body(ptr inttoptr (i64 2 to ptr))
+ %0 = call i1 @__quantum__qis__read_result__body(ptr null)
+ br i1 %0, label %then, label %else
+
+then: ; preds = %entry
+ call void @__quantum__qis__x__body(ptr null)
+ call void @__quantum__qis__cnot__body(ptr null, ptr inttoptr (i64 1 to ptr))
+ br label %continue
+
+else: ; preds = %entry
+ br label %continue
+
+continue: ; preds = %else, %then
+ %1 = call i1 @__quantum__qis__read_result__body(ptr inttoptr (i64 1 to ptr))
+ br i1 %1, label %then1, label %else2
+
+then1: ; preds = %continue
+ call void @__quantum__qis__cnot__body(ptr inttoptr (i64 1 to ptr), ptr inttoptr (i64 2 to ptr))
+ br label %continue3
+
+else2: ; preds = %continue
+ br label %continue3
+
+continue3: ; preds = %else2, %then1
+ %2 = call i1 @__quantum__qis__read_result__body(ptr inttoptr (i64 2 to ptr))
+ br i1 %2, label %then4, label %else5
+
+then4: ; preds = %continue3
+ br label %continue6
+
+else5: ; preds = %continue3
+ call void @__quantum__qis__h__body(ptr inttoptr (i64 2 to ptr))
+ br label %continue6
+
+continue6: ; preds = %else5, %then4
+ call void @__quantum__rt__result_record_output(ptr null, ptr null)
+ call void @__quantum__rt__result_record_output(ptr inttoptr (i64 1 to ptr), ptr null)
+ call void @__quantum__rt__result_record_output(ptr inttoptr (i64 2 to ptr), ptr null)
+ call void @__quantum__rt__result_record_output(ptr inttoptr (i64 3 to ptr), ptr null)
+ ret void
+}
+
+declare void @__quantum__rt__initialize(ptr)
+
+declare void @__quantum__qis__h__body(ptr)
+
+declare void @__quantum__qis__mz__body(ptr, ptr writeonly) #1
+
+declare void @__quantum__qis__reset__body(ptr)
+
+declare i1 @__quantum__qis__read_result__body(ptr)
+
+declare void @__quantum__qis__x__body(ptr)
+
+declare void @__quantum__qis__cnot__body(ptr, ptr)
+
+declare void @__quantum__rt__result_record_output(ptr, ptr)
+
+attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="base" "required_num_qubits"="4" "required_num_results"="4" }
+attributes #1 = { "irreversible" }
+
+!llvm.module.flags = !{!0, !1, !2, !3}
+
+!0 = !{i32 1, !"qir_major_version", i32 2}
+!1 = !{i32 7, !"qir_minor_version", i32 0}
+!2 = !{i32 1, !"dynamic_qubit_management", i1 false}
+!3 = !{i32 1, !"dynamic_result_management", i1 false}
diff --git a/tests/qasm3_qir/fixtures/resources/simple_if_typed.ll b/tests/qasm3_qir/fixtures/resources/simple_if_typed.ll
new file mode 100644
index 00000000..2813135a
--- /dev/null
+++ b/tests/qasm3_qir/fixtures/resources/simple_if_typed.ll
@@ -0,0 +1,86 @@
+; ModuleID = 'program-fe043bae-4572-11f0-be85-773714bb7840'
+source_filename = "program-fe043bae-4572-11f0-be85-773714bb7840"
+
+%Qubit = type opaque
+%Result = type opaque
+
+define void @main() #0 {
+entry:
+ call void @__quantum__rt__initialize(i8* null)
+ call void @__quantum__qis__h__body(%Qubit* null)
+ call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 1 to %Qubit*))
+ call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 2 to %Qubit*))
+ call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 3 to %Qubit*))
+ call void @__quantum__qis__mz__body(%Qubit* null, %Result* null)
+ call void @__quantum__qis__mz__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 1 to %Result*))
+ call void @__quantum__qis__mz__body(%Qubit* inttoptr (i64 2 to %Qubit*), %Result* inttoptr (i64 2 to %Result*))
+ call void @__quantum__qis__mz__body(%Qubit* inttoptr (i64 3 to %Qubit*), %Result* inttoptr (i64 3 to %Result*))
+ call void @__quantum__qis__reset__body(%Qubit* null)
+ call void @__quantum__qis__reset__body(%Qubit* inttoptr (i64 1 to %Qubit*))
+ call void @__quantum__qis__reset__body(%Qubit* inttoptr (i64 2 to %Qubit*))
+ %0 = call i1 @__quantum__qis__read_result__body(%Result* null)
+ br i1 %0, label %then, label %else
+
+then: ; preds = %entry
+ call void @__quantum__qis__x__body(%Qubit* null)
+ call void @__quantum__qis__cnot__body(%Qubit* null, %Qubit* inttoptr (i64 1 to %Qubit*))
+ br label %continue
+
+else: ; preds = %entry
+ br label %continue
+
+continue: ; preds = %else, %then
+ %1 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 1 to %Result*))
+ br i1 %1, label %then1, label %else2
+
+then1: ; preds = %continue
+ call void @__quantum__qis__cnot__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Qubit* inttoptr (i64 2 to %Qubit*))
+ br label %continue3
+
+else2: ; preds = %continue
+ br label %continue3
+
+continue3: ; preds = %else2, %then1
+ %2 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 2 to %Result*))
+ br i1 %2, label %then4, label %else5
+
+then4: ; preds = %continue3
+ br label %continue6
+
+else5: ; preds = %continue3
+ call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 2 to %Qubit*))
+ br label %continue6
+
+continue6: ; preds = %else5, %then4
+ call void @__quantum__rt__result_record_output(%Result* null, i8* null)
+ call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 1 to %Result*), i8* null)
+ call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 2 to %Result*), i8* null)
+ call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 3 to %Result*), i8* null)
+ ret void
+}
+
+declare void @__quantum__rt__initialize(i8*)
+
+declare void @__quantum__qis__h__body(%Qubit*)
+
+declare void @__quantum__qis__mz__body(%Qubit*, %Result* writeonly) #1
+
+declare void @__quantum__qis__reset__body(%Qubit*)
+
+declare i1 @__quantum__qis__read_result__body(%Result*)
+
+declare void @__quantum__qis__x__body(%Qubit*)
+
+declare void @__quantum__qis__cnot__body(%Qubit*, %Qubit*)
+
+declare void @__quantum__rt__result_record_output(%Result*, i8*)
+
+attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="base" "required_num_qubits"="4" "required_num_results"="4" }
+attributes #1 = { "irreversible" }
+
+!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}
diff --git a/tests/qir_utils.py b/tests/qir_utils.py
index dabf7b19..6802eb67 100644
--- a/tests/qir_utils.py
+++ b/tests/qir_utils.py
@@ -30,6 +30,7 @@
required_num_results,
)
+from qbraid_qir._pyqir_compat import pyqir_uses_opaque_pointers
from qbraid_qir.qasm3.maps import CONSTANTS_MAP
@@ -53,6 +54,10 @@ def assert_equal_qir(given_qir: str, filepath: str) -> None:
def _qubit_string(qubit: int) -> str:
+ if pyqir_uses_opaque_pointers():
+ if qubit == 0:
+ return "ptr null"
+ return f"ptr inttoptr (i64 {qubit} to ptr)"
if qubit == 0:
return "%Qubit* null"
return f"%Qubit* inttoptr (i64 {qubit} to %Qubit*)"
@@ -63,12 +68,18 @@ def _barrier_string() -> str:
def _result_string(res: int) -> str:
+ if pyqir_uses_opaque_pointers():
+ if res == 0:
+ return "ptr null"
+ return f"ptr inttoptr (i64 {res} to ptr)"
if res == 0:
return "%Result* null"
return f"%Result* inttoptr (i64 {res} to %Result*)"
def initialize_call_string() -> str:
+ if pyqir_uses_opaque_pointers():
+ return "call void @__quantum__rt__initialize(ptr null)"
return "call void @__quantum__rt__initialize(i8* null)"
@@ -97,11 +108,13 @@ def measure_call_string(name: str, res: str, qb: int) -> str:
def array_record_output_string(num_elements: int) -> str:
- return f"call void @__quantum__rt__array_record_output(i64 {num_elements}, i8* null)"
+ null_arg = "ptr null" if pyqir_uses_opaque_pointers() else "i8* null"
+ return f"call void @__quantum__rt__array_record_output(i64 {num_elements}, {null_arg})"
def result_record_output_string(res: str) -> str:
- return f"call void @__quantum__rt__result_record_output({_result_string(res)}, i8* null)"
+ null_arg = "ptr null" if pyqir_uses_opaque_pointers() else "i8* null"
+ return f"call void @__quantum__rt__result_record_output({_result_string(res)}, {null_arg})"
def reset_call_string(qb: int) -> str:
diff --git a/tests/squin_qir/test_cudaq_to_squin.py b/tests/squin_qir/test_cudaq_to_squin.py
index 3a4fd8a6..28f9a042 100644
--- a/tests/squin_qir/test_cudaq_to_squin.py
+++ b/tests/squin_qir/test_cudaq_to_squin.py
@@ -14,11 +14,14 @@
"""Unit tests for CUDAQ to Squin conversion functions."""
-import cudaq
+import pytest
-from qbraid_qir.squin import load
+cudaq = pytest.importorskip("cudaq")
-from .test_qir_to_squin import _compare_output
+# Imports after importorskip so optional dependency is not required at import time.
+from qbraid_qir.squin import load # pylint: disable=wrong-import-position
+
+from .test_qir_to_squin import _compare_output # pylint: disable=wrong-import-position
def test_bell_state():
diff --git a/tests/squin_qir/test_qir_to_squin.py b/tests/squin_qir/test_qir_to_squin.py
index 7b4bf03b..73374ce6 100644
--- a/tests/squin_qir/test_qir_to_squin.py
+++ b/tests/squin_qir/test_qir_to_squin.py
@@ -13,6 +13,7 @@
# limitations under the License.
"""Unit tests for QIR to Squin conversion functions."""
+
import os
import re
diff --git a/tox.ini b/tox.ini
index e62cabfa..fbd683b2 100644
--- a/tox.ini
+++ b/tox.ini
@@ -2,6 +2,8 @@
minversion = 4.2.0
envlist =
unit-tests
+ unit-tests-pyqir11
+ unit-tests-pyqir12
docs
linters
format-check
@@ -12,11 +14,38 @@ commands_pre = python -m pip install .
basepython = python3
[testenv:unit-tests]
-description = Run pytests and generate coverage report.
+description = Run pytests and generate coverage report (default pyqir).
+deps = -r {toxinidir}/requirements-test.txt
extras =
cirq
qasm3
+ squin
+commands =
+ pytest tests --cov=qbraid_qir --cov-config=pyproject.toml --cov-report=term --cov-report=xml {posargs}
+
+[testenv:unit-tests-pyqir11]
+description = Run unit tests with pyqir 0.11.x (typed pointers).
+deps = -r {toxinidir}/requirements-test.txt
+extras =
+ cirq
+ qasm3
+ squin
+ test
+commands_pre =
+ python -m pip install "pyqir>=0.10.0,<0.12"
+commands =
+ pytest tests --cov=qbraid_qir --cov-config=pyproject.toml --cov-report=term --cov-report=xml {posargs}
+
+[testenv:unit-tests-pyqir12]
+description = Run unit tests with pyqir 0.12+ (opaque pointers).
+deps = -r {toxinidir}/requirements-test.txt
+extras =
+ cirq
+ qasm3
+ squin
test
+commands_pre =
+ python -m pip install "pyqir>=0.12.0,<0.13.0"
commands =
pytest tests --cov=qbraid_qir --cov-config=pyproject.toml --cov-report=term --cov-report=xml {posargs}
@@ -57,7 +86,7 @@ commands =
[testenv:headers]
envdir = .tox/linters
skip_install = true
-deps = qbraid-cli>=0.10.1
+deps = qbraid-cli>=0.12.0
commands =
qbraid admin headers tests bin qbraid_qir docker --type=apache {posargs}