This folder contains the Quantum Intermediate Representation (QIR) Runtime project. The QIR is a subset of the LLVM Intermediate Representation. The QIR runtime includes an implementation of the QIR specification and the bridge to run QIR against the native full state simulator.
public
folder contains the public headerslib
folder contains the implementation of the runtime and the simulators.unittests
folder contains tests for the runtimeExternals
folder contains external dependencies. We'll strive to keep those minimal.
The QirRuntime project is using CMake (3.17) + Ninja(1.10.0) + Clang++(11.0.0). Other versions of the tools might work
but haven't been tested. Only x64 architecture is supported.
For running the PowerShell scripts below use
PowerShell Core or PowerShell 7+ (pwsh
), not the inbox PowerShell.
To install prerequisite tools for building the QIR runtime, you can set the ENABLE_QIRRUNTIME
environment variable to the string "true"
and run prerequisites.ps1
, or manually install pre-reqs with the steps listed below.
Note that on Windows, this script relies on the Chocolatey package manager,
while on macOS, prerequisites.ps1
relies on the brew
package manager.
- Install Clang 13, Ninja and CMake from the public distros.
- Add all three to your/system
%PATH%
. - Install VS 2019 and enable "Desktop development with C++" component (Clang uses MSVC's standard library on Windows).
- Install clang-tidy and clang-format if your Clang/LLVM packages didn't include the tools.
- Install the same version of dotnet as specified by qsharp-runtime README
Building from Visual Studio and VS Code is not supported. Running cmake from the editors will likely default to MSVC or clang-cl and fail.
- On the host Windows machine enable WSL and install Ubuntu 20.04 LTS.
- In the Ubuntu's terminal:
$ sudo apt install cmake
($ cmake --version
should return 3.16.3)$ sudo apt-get install ninja-build
($ ninja --version
should return 1.10.0)$ sudo apt install clang-13
($ clang++-13 --version
should return 13.0.0)- Set Clang as the preferred C/C++ compiler:
- $ export CC=/usr/bin/clang-13
- $ export CXX=/usr/bin/clang++-13
$ sudo apt install clang-tidy-13
($ clang-tidy-13 --version
should return 'LLVM version 13.0.0')- Install the same version of dotnet as specified by qsharp-runtime README
See [https://code.visualstudio.com/docs/remote/wsl] on how to use VS Code with WSL.
The build depends on Microsoft.Quantum.Simulator.Runtime
dynamic library built at a higher level of the directory tree.
To build that library follow the instructions in qsharp-runtime/README.md
(up to and including the step Simulation.sln
).
To build QirRuntime you can run build-qir-runtime.ps1
script from QirRuntime folder:
pwsh build-qir-runtime.ps1
The script will create the build/{Debug|Release}
folder and place the build artifacts in it. The configuration Debug|Release
is specified with the BUILD_CONFIGURATION
environment variable.
If the variable is not set then the default is specified in set-env.ps1
.
The tests in the unittests
folder are those that are compiled directly against the object libraries
from the runtime, and verify behavior of the runtime using more than the public API. For tests that
verify behavior of the public API surface using compiled QIR from Q# projects, see the src/Qir/Tests
folder.
# Navigate to QirRuntime folder.
pwsh test-qir-runtime.ps1
<test_binary> -help
provides details on how to run a subset of the tests and other options. For example, you can
filter tests from the "[skip]" category out by <test_binary> ~[skip]
.
For tests that depend on the native simulator and qdk shared libraries, you might need to modify the corresponding dynamic libraries lookup path environment variable:
- (Windows) PATH
- (Unix) LD_LIBRARY_PATH
- (Darwin) DYLD_LIBRARY_PATH
This project contains an implementation of the QIR runtime per the QIR specifications and the translation layer between the QIR and the IR, generated by Clang from the native code. Translation layer is called the "QIR Bridge".
This project also provides an implementation of the quantum instruction set, used by Q# for simulation against the full state simulator:
operation Exp (paulis : Pauli[], theta : Double, qubits : Qubit[]) : Unit is Adj + Ctl
void @__quantum__qis__exp__body(%Array*, double, %Array*)
void @__quantum__qis__exp__adj(%Array*, double, %Array*)
void @__quantum__qis__exp__ctl(%Array*, { %Array*, double, %Array* }*)
void @__quantum__qis__exp__ctladj(%Array*, { %Array*, double, %Array* }*)
void @__quantum__qis__h__body(%Qubit*)
void @__quantum__qis__h__ctl(%Array*, %Qubit*)
%Result* @__quantum__qis__measure__body(%Array*, %Array*)
void @__quantum__qis__r__body(i2, double, %Qubit*)
void @__quantum__qis__r__adj(i2, double, %Qubit*)
void @__quantum__qis__r__ctl(%Array*, { i2, double, %Qubit* }*)
void @__quantum__qis__r__ctladj(%Array*, { i2, double, %Qubit* }*)
void @__quantum__qis__s__body(%Qubit*)
void @__quantum__qis__s__adj(%Qubit*)
void @__quantum__qis__s__ctl(%Array*, %Qubit*)
void @__quantum__qis__s__ctladj(%Array*, %Qubit*)
void @__quantum__qis__t__body(%Qubit*)
void @__quantum__qis__t__adj(%Qubit*)
void @__quantum__qis__t__ctl(%Array*, %Qubit*)
void @__quantum__qis__t__ctladj(%Array*, %Qubit*)
void @__quantum__qis__x__body(%Qubit*)
void @__quantum__qis__x__ctl(%Array*, %Qubit*)
void @__quantum__qis__y__body(%Qubit*)
void @__quantum__qis__y__ctl(%Array*, %Qubit*)
void @__quantum__qis__z__body(%Qubit*)
void @__quantum__qis__z__ctl(%Array*, %Qubit*)
There are two ways to compile and run the QIR files against the runtime.
- Link against the runtime libraries statically. For the example of this approach see
test/QIR-static
tests. It allows the client to access the target simulator directly, if so desired. - Link against the shared qdk library. The example of this approach can be found in
test/QIR-dynamic
folder. In the future we'll provide fully self-contained packages of the runtime to enable this workflow completely outside of the current project. For now, this way of consuming QIR only supports running against the native full state simulator.
QIR's architecture assumes a single target, whether that be hardware or a particular simulator. As a result, there is no
provision in the QIR specifications to choose a target dynamically. To connect QIR to the simulators from this runtime,
we provide QirExecutionContext::Init()
(earlier InitializeQirContext
)
and QirExecutionContext::Deinit()
(earlier ReleaseQirContext
) methods.
Switching contexts while executing QIR isn't supported and would yield undefined behavior.
CMake doesn't support using LLVM's IR files as input so instead we invoke Clang directly from custom commands to create utility libs that can be linked into other targets using their absolute paths.
NB: Compiling from IR has fewer checks than compiling from C++. For example, IR doesn't support overloading so declarations and definitions of functions are matched by name, without taking into account the arguments. This means that a build might succeed with mismatched signatures between caller/callee which will likely lead to crashes and other bugs at runtime.
The QIR runtime is work in progress. Current known limitations are as follows:
- All functionality related to BigInt type (including
__quantum__rt__bigint_to_string
) NYI. - QIR is assumed to be single threaded. No effort was made to make the bridge and runtime thread safe.
- Strings are implemented as a thin wrapper over std::string with virtually no optimizations.
- Variadic functions (e.g.
__quantum__rt__array_create
) require platform specific bridges. The currently implemented bridge is for Windows. - Qubit borrowing NYI (needs both bridge and simulator's support).
If during compilation you see an error like this
##vso[task.logissue type=error;]Formatting check failed. The following files need to be formatted before compiling:
then this means that the edits you made violate the
coding style
enforced by clang-format utility. To format the file install the
Clang-Format extension to your editor (example for VSCode),
open the file, press the corresponding formatting hot keys (for VSCode it is <Alt+Shift+f>), and save the file.
See more links in .clang-format file.
Most of our coding style and conventions are enforced via clang-tidy. The project is currently set up to treat
clang-tidy warnings as build errors and we'd like to keep it this way. If you absolutely need to violate the style,
mark the problematic line with // NOLINT
. To suppress style checks in a whole folder, add .clang-tidy file into the
folder with checks reduced to Checks: '-*,bugprone-*'
.
Clang-tidy checks reference: [https://clang.llvm.org/extra/clang-tidy/checks/list.html]
Conventions not covered by .clang-format and .clang-tidy:
- fields of a class/struct must be placed at the top of the class/struct definition;
- must use
this
to access class and struct members:this->fooBar
; - Interface declarations should be placed in separate header files with "_I" suffix.:
FooBar_I.hpp
.