Skip to content

Latest commit

 

History

History
197 lines (149 loc) · 10.1 KB

README.md

File metadata and controls

197 lines (149 loc) · 10.1 KB

The Native QIR Runtime

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 headers
  • lib folder contains the implementation of the runtime and the simulators.
  • unittests folder contains tests for the runtime
  • Externals folder contains external dependencies. We'll strive to keep those minimal.

Build

Prerequisites

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.

Windows pre-reqs

  1. Install Clang 13, Ninja and CMake from the public distros.
  2. Add all three to your/system %PATH%.
  3. Install VS 2019 and enable "Desktop development with C++" component (Clang uses MSVC's standard library on Windows).
  4. Install clang-tidy and clang-format if your Clang/LLVM packages didn't include the tools.
  5. 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.

Linux via WSL pre-reqs

  1. On the host Windows machine enable WSL and install Ubuntu 20.04 LTS.
  2. In the Ubuntu's terminal:
    1. $ sudo apt install cmake ($ cmake --version should return 3.16.3)
    2. $ sudo apt-get install ninja-build ($ ninja --version should return 1.10.0)
    3. $ sudo apt install clang-13 ($ clang++-13 --version should return 13.0.0)
    4. Set Clang as the preferred C/C++ compiler:
      • $ export CC=/usr/bin/clang-13
      • $ export CXX=/usr/bin/clang++-13
    5. $ sudo apt install clang-tidy-13 ($ clang-tidy-13 --version should return 'LLVM version 13.0.0')
    6. 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.

Other Prerequisites

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).

Build Commands

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.

Tests

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.

Running All Tests

# Navigate to QirRuntime folder.

pwsh test-qir-runtime.ps1

Running Test Binaries Individually

<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

QIR Bridge and Runtime

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".

QIR Bridge architecture diagram

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.

  1. 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.
  2. 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.

Building from IR files

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:

  1. All functionality related to BigInt type (including __quantum__rt__bigint_to_string) NYI.
  2. QIR is assumed to be single threaded. No effort was made to make the bridge and runtime thread safe.
  3. Strings are implemented as a thin wrapper over std::string with virtually no optimizations.
  4. Variadic functions (e.g. __quantum__rt__array_create) require platform specific bridges. The currently implemented bridge is for Windows.
  5. Qubit borrowing NYI (needs both bridge and simulator's support).

Coding style and conventions

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.