Skip to content
This repository has been archived by the owner on Jan 12, 2024. It is now read-only.

Commit

Permalink
Update projects, docs, cpp files for QIR stdlib (#1578)
Browse files Browse the repository at this point in the history
* Update projects, docs, cpp files for QIR stdlib

This change updates the remaining example and test projects for using the QIR stdlib via the Microsoft.Quantum.Simulator.Runtime as a QIR backend. This resolves #1560, resolves #1568, and resolves #1569.

Note that it does not update the samples under examples\QIR\Simulation as these need to be fully rewritten and likely moved to https://github.com/qir-alliance/qir-runner (see Rewrite or Move docs in examples/QIR/Simulation #1577)

* Fix development project QDK version

* Update examples/QIR/Optimization/README.md

Co-authored-by: Robin Kuzmin <9372582+kuzminrobin@users.noreply.github.com>

* Use alternative method for copying build dependencies

Co-authored-by: Robin Kuzmin <9372582+kuzminrobin@users.noreply.github.com>
  • Loading branch information
swernli and kuzminrobin committed Dec 7, 2022
1 parent 82e9304 commit 35ac6ce
Show file tree
Hide file tree
Showing 12 changed files with 68 additions and 2,220 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,7 @@ src/ProjectTemplates/Quantum.Test1/.template.config/template.json
src/QsCompiler/QirGeneration/QirGeneration.nuspec
/examples/QIR/Development/qir/*
/examples/QIR/Development/build
/examples/QIR/Optimization/Hello/build
src/Telemetry/Tests/coverage.json
src/Telemetry/.vscode/settings.json
build/267DevDivSNKey2048.snk
Expand Down
35 changes: 9 additions & 26 deletions examples/QIR/Development/Development.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.Quantum.Sdk/0.25.228311"> <!-- TODO(#1569): Requires refactoring for Rust QIR RT. -->
<Project Sdk="Microsoft.Quantum.Sdk/0.27.238334">

<PropertyGroup>
<OutputType>Exe</OutputType>
Expand All @@ -9,8 +9,7 @@

<ItemGroup>
<PackageReference Include="Microsoft.Quantum.LlvmBindings.Native" Version="13.0.0-CI-20220129-005156" PrivateAssets="All" GeneratePathProperty="true"/>
<PackageReference Include="Microsoft.Quantum.Qir.Runtime" Version="0.25.228311-alpha" GeneratePathProperty="true" /> <!-- TODO(#1569): Requires refactoring for Rust QIR RT. -->
<PackageReference Include="Microsoft.Quantum.Simulators" Version="0.25.228311" GeneratePathProperty="true" />
<PackageReference Include="Microsoft.Quantum.Simulators" Version="0.27.238334" GeneratePathProperty="true" />
</ItemGroup>

<PropertyGroup>
Expand Down Expand Up @@ -92,18 +91,9 @@
<Target Name="CreateCppDriver">
<PropertyGroup>
<DriverCode>
#include "QirContext.hpp"
#include "QirRuntime.hpp"
#include "SimFactory.hpp"

using namespace Microsoft::Quantum%3B
using namespace std%3B

extern "C" void Microsoft__Quantum__Qir__Development__RunExample()%3B // NOLINT

int main(int argc, char* argv[]){
unique_ptr&lt;IRuntimeDriver&gt; sim = CreateFullstateSimulator()%3B
QirContextScope qirctx(sim.get(), true /*trackAllocatedObjects*/)%3B
Microsoft__Quantum__Qir__Development__RunExample()%3B
return 0%3B
}
Expand All @@ -114,24 +104,17 @@

<Target Name="BuildExecutable" Condition="'$(DesignTimeBuild)' != 'true'" DependsOnTargets="CreateCppDriver;Restore" AfterTargets="QSharpCompile;CoreBuild">
<PropertyGroup>
<QirRuntimeHeaders>$(PkgMicrosoft_Quantum_Qir_Runtime)/runtimes/any/native/include</QirRuntimeHeaders>
<QirRuntimeLibs Condition="$([MSBuild]::IsOsPlatform('OSX'))">$(PkgMicrosoft_Quantum_Qir_Runtime)/runtimes/osx-x64/native</QirRuntimeLibs>
<QirRuntimeLibs Condition="$([MSBuild]::IsOsPlatform('Windows'))">$(PkgMicrosoft_Quantum_Qir_Runtime)/runtimes/win-x64/native</QirRuntimeLibs>
<QirRuntimeLibs Condition="$([MSBuild]::IsOsPlatform('Linux'))">$(PkgMicrosoft_Quantum_Qir_Runtime)/runtimes/linux-x64/native</QirRuntimeLibs>
<SimulatorRuntime Condition="$([MSBuild]::IsOsPlatform('OSX'))">$(PkgMicrosoft_Quantum_Simulators)/runtimes/osx-x64/native/libMicrosoft.Quantum.Simulator.Runtime.dylib</SimulatorRuntime>
<SimulatorRuntime Condition="$([MSBuild]::IsOsPlatform('Windows'))">$(PkgMicrosoft_Quantum_Simulators)/runtimes/win-x64/native/Microsoft.Quantum.Simulator.Runtime.dll</SimulatorRuntime>
<SimulatorRuntime Condition="$([MSBuild]::IsOsPlatform('Linux'))">$(PkgMicrosoft_Quantum_Simulators)/runtimes/linux-x64/native/libMicrosoft.Quantum.Simulator.Runtime.so</SimulatorRuntime>
<SimulatorFolder Condition="$([MSBuild]::IsOsPlatform('OSX'))">$(PkgMicrosoft_Quantum_Simulators)/runtimes/osx-x64/native</SimulatorFolder>
<SimulatorFolder Condition="$([MSBuild]::IsOsPlatform('Windows'))">$(PkgMicrosoft_Quantum_Simulators)/runtimes/win-x64/native</SimulatorFolder>
<SimulatorFolder Condition="$([MSBuild]::IsOsPlatform('Linux'))">$(PkgMicrosoft_Quantum_Simulators)/runtimes/linux-x64/native</SimulatorFolder>
<ClangOptions Condition="$([MSBuild]::IsOsPlatform('Linux')) Or $([MSBuild]::IsOsPlatform('OSX'))">-fseh-exceptions -lstdc++</ClangOptions>
<ClangCommand>clang -std=c++17 -Wno-override-module $(ClangOptions) -o $(ExecutablePath) $(QirOutputPath)$(PathCompatibleAssemblyName).ll $(BuildOutputPath)/Main.cpp -I$(BuildOutputPath) -L$(BuildOutputPath) -lMicrosoft.Quantum.Qir.Runtime -lMicrosoft.Quantum.Qir.QSharp.Core -lMicrosoft.Quantum.Qir.QSharp.Foundation</ClangCommand>
<OmpOptions Condition="$([MSBuild]::IsOsPlatform('Linux'))">-lomp</OmpOptions>
<ClangCommand>clang -std=c++17 -Wno-override-module $(ClangOptions) -o $(ExecutablePath) $(QirOutputPath)$(PathCompatibleAssemblyName).ll $(BuildOutputPath)/Main.cpp -I$(BuildOutputPath) -L$(BuildOutputPath) -lMicrosoft.Quantum.Simulator.Runtime $(OmpOptions)</ClangCommand>
</PropertyGroup>
<ItemGroup>
<_QirRuntimeLibFiles Include="$(QirRuntimeLibs)/**/*.*" Exclude="$(QirRuntimeLibs)/**/*.exe" />
<_QirRuntimeHeaderFiles Include="$(QirRuntimeHeaders)/**/*.hpp" />
<_QirRuntimeHeaderFiles Include="$(QirRuntimeHeaders)/**/*.h" />
<_SimulatorLibraries Include="$(SimulatorFolder)/*.*" />
</ItemGroup>
<Copy SourceFiles="$(SimulatorRuntime)" DestinationFolder="$(BuildOutputPath)" SkipUnchangedFiles="true" />
<Copy SourceFiles="@(_QirRuntimeLibFiles)" DestinationFolder="$(BuildOutputPath)\%(RecursiveDir)" SkipUnchangedFiles="true" />
<Copy SourceFiles="@(_QirRuntimeHeaderFiles)" DestinationFolder="$(BuildOutputPath)\%(RecursiveDir)" SkipUnchangedFiles="true" />
<Copy SourceFiles="@(_SimulatorLibraries)" DestinationFolder="$(BuildOutputPath)" SkipUnchangedFiles="true" />
<Exec Command="clang --version" IgnoreExitCode="true" ContinueOnError="ErrorAndContinue">
<Output TaskParameter="ExitCode" PropertyName="ClangVersionCheckExitCode"/>
</Exec>
Expand Down
2 changes: 1 addition & 1 deletion examples/QIR/Emission/Emission.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.Quantum.Sdk/0.25.228311"> <!-- TODO(#1569): Requires refactoring for Rust QIR RT. -->
<Project Sdk="Microsoft.Quantum.Sdk/0.27.238334">

<PropertyGroup>
<QscVerbosity>Detailed</QscVerbosity>
Expand Down
70 changes: 14 additions & 56 deletions examples/QIR/JITCompilation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ The function below is all that is needed to JIT compile a QIR program, and consi
- load QIR/simulator libraries
- parse the QIR program
- load the JIT compiler
- initialize the QIR Runtime and attach a simulator (see [next section](#building-the-project) for more info)
- initialize and attach a simulator (see [next section](#building-the-project) for more info)
- run a QIR function

```py
Expand All @@ -48,9 +48,8 @@ def main(qir_file, entry_point):
llvm.initialize_native_target()
llvm.initialize_native_asmprinter()

# Load the QIR Runtime libraries
for lib in runtime_libs:
llvm.load_library_permanently(lib)
# Load the simulator library
llvm.load_library_permanently(simulator_lib)

# Parse the provided QIR module
file = open(qir_file, 'r')
Expand All @@ -60,16 +59,12 @@ def main(qir_file, entry_point):
target = llvm.Target.from_default_triple().create_target_machine()
jit_engine = llvm.create_mcjit_compiler(module, target)

# Initialize the QIR Runtime and simulator via exposed C wrapper
fun_ptr = llvm.address_of_symbol("InitQIRSim")
CFUNCTYPE(None)(fun_ptr)()

# Run the entry point of the QIR module
fun_ptr = jit_engine.get_function_address(entry_point)
CFUNCTYPE(None)(fun_ptr)()
```

Here, `runtime_libs` is a hardcoded list of the system-specific QIR libraries.
Here, `simulator_lib` is the platform specific path to the simulator library.
The name of the QIR source file `qir_file` is provided as a command-line argument, as well the name of the entry point function `entry_point`.

The way external functions with C-style linkage are invoked from Python is by using the ctypes module.
Expand All @@ -78,44 +73,22 @@ The returned value is a raw pointer that can be converted to a function pointer
This is done via the function `CFUNCTYPE(<return type>, <argument types>..)(<ptr_name>)`, which also specifies the usage of the standard C calling convention.
Refer to the [ctypes documentation](https://docs.python.org/3/library/ctypes.html) for more information on calling external functions from Python.

The full Python script can be found in `jit-qir.py`.
The full Python script can be found in `qir-jit.py`.

## Building the project

Currently, it's not easily possible to set up a JIT for QIR entirely from Python, since the QIR Runtime and simulator are compiled from C++.
To get around this, a small library for which we can specify C-linkage can handle the QIR-specific initialization, which can then be invoked from Python directly using ctypes.
A small function declared with `extern "C"` linkage is sufficient to initialize the Runtime + simulator, as defined in `QIRinit.cpp`:

```cpp
#include "QirContext.hpp"
#include "SimFactory.hpp"
Before being able run QIR via LLVM's JIT compiler, we need to download the necessary simulator library from the [Quantum Simulators](https://www.nuget.org/packages/Microsoft.Quantum.Simulators/) NuGet packages:

#include <memory>

using namespace Microsoft::Quantum;

extern "C" void InitQIRSim()
{
// initialize Quantum Simulator and QIR Runtime
std::unique_ptr<IRuntimeDriver> sim = CreateFullstateSimulator();
InitializeQirContext(sim.release(), true);
}
```
Before being able run QIR via LLVM's JIT compiler, we need to download the necessary header and library files from the [QIR Runtime](https://www.nuget.org/packages/Microsoft.Quantum.Qir.Runtime) and [Quantum Simulators](https://www.nuget.org/packages/Microsoft.Quantum.Simulators/) NuGet packages:
- **Linux** (installs mono for the NuGet CLI):
- **Linux** (install mono for the NuGet CLI):

```shell
mkdir build
sudo apt update && sudo apt install -y mono-complete
curl https://dist.nuget.org/win-x86-commandline/latest/nuget.exe --output build/nuget
mono build/nuget sources add -name nuget.org -source https://api.nuget.org/v3/index.json
mono build/nuget install Microsoft.Quantum.Qir.Runtime -Version 0.18.2106148911-alpha -DirectDownload -DependencyVersion Ignore -OutputDirectory tmp
cp tmp/Microsoft.Quantum.Qir.Runtime.0.18.2106148911-alpha/runtimes/any/native/include/* build
cp tmp/Microsoft.Quantum.Qir.Runtime.0.18.2106148911-alpha/runtimes/linux-x64/native/* build
mono build/nuget install Microsoft.Quantum.Simulators -Version 0.18.2106148911 -DirectDownload -DependencyVersion Ignore -OutputDirectory tmp
cp tmp/Microsoft.Quantum.Simulators.0.18.2106148911/runtimes/linux-x64/native/Microsoft.Quantum.Simulator.Runtime.dll build
mono build/nuget install Microsoft.Quantum.Simulators -Version 0.27.238334 -DirectDownload -DependencyVersion Ignore -OutputDirectory tmp
cp tmp/Microsoft.Quantum.Simulators.0.27.238334/runtimes/linux-x64/native/libMicrosoft.Quantum.Simulator.Runtime.so build
cp tmp/Microsoft.Quantum.Simulators.0.27.238334/runtimes/linux-x64/native/libomp.so build
rm -r tmp
```

Expand All @@ -124,28 +97,13 @@ Before being able run QIR via LLVM's JIT compiler, we need to download the neces
```shell
mkdir build
curl https://dist.nuget.org/win-x86-commandline/latest/nuget.exe --output build/nuget.exe
build/nuget install Microsoft.Quantum.Qir.Runtime -Version 0.18.2106148911-alpha -DirectDownload -DependencyVersion Ignore -OutputDirectory tmp
cp tmp/Microsoft.Quantum.Qir.Runtime.0.18.2106148911-alpha/runtimes/any/native/include/* build
cp tmp/Microsoft.Quantum.Qir.Runtime.0.18.2106148911-alpha/runtimes/win-x64/native/* build
build/nuget install Microsoft.Quantum.Simulators -Version 0.18.2106148911 -DirectDownload -DependencyVersion Ignore -OutputDirectory tmp
cp tmp/Microsoft.Quantum.Simulators.0.18.2106148911/runtimes/win-x64/native/Microsoft.Quantum.Simulator.Runtime.dll build
build/nuget install Microsoft.Quantum.Simulators -Version 0.27.238334 -DirectDownload -DependencyVersion Ignore -OutputDirectory tmp
cp tmp/Microsoft.Quantum.Simulators.0.27.238334/runtimes/win-x64/native/Microsoft.Quantum.Simulator.Runtime.dll build
cp tmp/Microsoft.Quantum.Simulators.0.27.238334/runtimes/win-x64/native/Microsoft.Quantum.Simulator.Runtime.lib build
cp tmp/Microsoft.Quantum.Simulators.0.27.238334/runtimes/win-x64/native/libomp140.x86_64.dll build
rm -r tmp
```

Then compile the initialization library with the following command:

- **Linux**:

```shell
clang++ -shared -fPIC QIRinit.cpp -Ibuild -o build/libQIRinit.so
```

- **Windows**:

```shell
clang++ -shared QIRinit.cpp -Ibuild -Lbuild -l'Microsoft.Quantum.Qir.Runtime' -l'Microsoft.Quantum.Qir.QSharp.Core' -Wl',/EXPORT:InitQIRSim' -o build/QIRinit.dll
```

## Running a QIR program with JIT

To run any QIR program through the JIT, simply run the Python script and provide the QIR source file name and entry point as command line arguments, for example:
Expand Down
27 changes: 7 additions & 20 deletions examples/QIR/JITCompilation/qir-jit.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,14 @@
import llvmlite.binding as llvm
from ctypes import CFUNCTYPE

linux_runtime_libs = ["build/libMicrosoft.Quantum.Qir.Runtime.so",
"build/libMicrosoft.Quantum.Qir.QSharp.Core.so",
"build/libMicrosoft.Quantum.Qir.QSharp.Foundation.so",
"build/Microsoft.Quantum.Simulator.Runtime.dll",
"build/libQIRinit.so"]

windows_runtime_libs = ["build/Microsoft.Quantum.Qir.Runtime.dll",
"build/Microsoft.Quantum.Qir.QSharp.Core.dll",
"build/Microsoft.Quantum.Qir.QSharp.Foundation.dll",
"build/Microsoft.Quantum.Simulator.Runtime.dll",
"build/QIRinit.dll"]
linux_simulator_lib = "build/libMicrosoft.Quantum.Simulator.Runtime.so"

windows_simulator_lib = "build/Microsoft.Quantum.Simulator.Runtime.dll"

if platform.system() == "Linux":
runtime_libs = linux_runtime_libs
simulator_lib = linux_simulator_lib
elif platform.system() == "Windows":
runtime_libs = windows_runtime_libs
simulator_lib = windows_simulator_lib
else:
raise Exception("unsupported platform")

Expand All @@ -27,9 +19,8 @@ def main(qir_file, entry_point):
llvm.initialize_native_target()
llvm.initialize_native_asmprinter()

# Load the QIR Runtime libraries
for lib in runtime_libs:
llvm.load_library_permanently(lib)
# Load the simulator library
llvm.load_library_permanently(simulator_lib)

# Parse the provided QIR module
file = open(qir_file, 'r')
Expand All @@ -39,10 +30,6 @@ def main(qir_file, entry_point):
target = llvm.Target.from_default_triple().create_target_machine()
jit_engine = llvm.create_mcjit_compiler(module, target)

# Initialize the QIR Runtime and simulator via exposed C wrapper
fun_ptr = llvm.address_of_symbol("InitQIRSim")
CFUNCTYPE(None)(fun_ptr)()

# Run the entry point of the QIR module
fun_ptr = jit_engine.get_function_address(entry_point)
CFUNCTYPE(None)(fun_ptr)()
Expand Down
23 changes: 7 additions & 16 deletions examples/QIR/Optimization/Hello/Hello.csproj
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<Project Sdk="Microsoft.Quantum.Sdk/0.25.228311"> <!-- TODO(#1569): Requires refactoring for Rust QIR RT. -->

<Project Sdk="Microsoft.Quantum.Sdk/0.27.238334">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
Expand All @@ -8,27 +7,19 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Quantum.Qir.Runtime" Version="0.25.228311-alpha" GeneratePathProperty="true" /> <!-- TODO(#1569): Requires refactoring for Rust QIR RT. -->
<PackageReference Include="Microsoft.Quantum.Simulators" Version="0.25.228311" GeneratePathProperty="true" />
<PackageReference Include="Microsoft.Quantum.Simulators" Version="0.27.238334" GeneratePathProperty="true" />
</ItemGroup>

<Target Name="GetDependencies" AfterTargets="Build">
<PropertyGroup>
<QirRuntimeHeaders>$(PkgMicrosoft_Quantum_Qir_Runtime)/runtimes/any/native/include</QirRuntimeHeaders>
<QirRuntimeLibs Condition="$([MSBuild]::IsOsPlatform('OSX'))">$(PkgMicrosoft_Quantum_Qir_Runtime)/runtimes/osx-x64/native</QirRuntimeLibs>
<QirRuntimeLibs Condition="$([MSBuild]::IsOsPlatform('Windows'))">$(PkgMicrosoft_Quantum_Qir_Runtime)/runtimes/win-x64/native</QirRuntimeLibs>
<QirRuntimeLibs Condition="$([MSBuild]::IsOsPlatform('Linux'))">$(PkgMicrosoft_Quantum_Qir_Runtime)/runtimes/linux-x64/native</QirRuntimeLibs>
<SimulatorRuntime Condition="$([MSBuild]::IsOsPlatform('OSX'))">$(PkgMicrosoft_Quantum_Simulators)/runtimes/osx-x64/native/Microsoft.Quantum.Simulator.Runtime.dll</SimulatorRuntime>
<SimulatorRuntime Condition="$([MSBuild]::IsOsPlatform('Windows'))">$(PkgMicrosoft_Quantum_Simulators)/runtimes/win-x64/native/Microsoft.Quantum.Simulator.Runtime.dll</SimulatorRuntime>
<SimulatorRuntime Condition="$([MSBuild]::IsOsPlatform('Linux'))">$(PkgMicrosoft_Quantum_Simulators)/runtimes/linux-x64/native/Microsoft.Quantum.Simulator.Runtime.dll</SimulatorRuntime>
<SimulatorFolder Condition="$([MSBuild]::IsOsPlatform('OSX'))">$(PkgMicrosoft_Quantum_Simulators)/runtimes/osx-x64/native</SimulatorFolder>
<SimulatorFolder Condition="$([MSBuild]::IsOsPlatform('Windows'))">$(PkgMicrosoft_Quantum_Simulators)/runtimes/win-x64/native</SimulatorFolder>
<SimulatorFolder Condition="$([MSBuild]::IsOsPlatform('Linux'))">$(PkgMicrosoft_Quantum_Simulators)/runtimes/linux-x64/native</SimulatorFolder>
</PropertyGroup>
<ItemGroup>
<_QirRuntimeLibFiles Include="$(QirRuntimeLibs)/**/*.*" Exclude="$(QirRuntimeLibs)/**/*.exe" />
<_QirRuntimeHeaderFiles Include="$(QirRuntimeHeaders)/**/*.hpp" />
<_SimulatorLibraries Include="$(SimulatorFolder)/*.*" />
</ItemGroup>
<Copy SourceFiles="$(SimulatorRuntime)" DestinationFolder="$(BuildOutputPath)" SkipUnchangedFiles="true" />
<Copy SourceFiles="@(_QirRuntimeLibFiles)" DestinationFolder="$(BuildOutputPath)\%(RecursiveDir)" SkipUnchangedFiles="true" />
<Copy SourceFiles="@(_QirRuntimeHeaderFiles)" DestinationFolder="$(BuildOutputPath)\%(RecursiveDir)" SkipUnchangedFiles="true" />
<Copy SourceFiles="@(_SimulatorLibraries)" DestinationFolder="$(BuildOutputPath)" SkipUnchangedFiles="true" />
</Target>

</Project>
9 changes: 0 additions & 9 deletions examples/QIR/Optimization/Hello/Main.cpp
Original file line number Diff line number Diff line change
@@ -1,15 +1,6 @@
#include "QirContext.hpp"
#include "QirRuntime.hpp"
#include "SimFactory.hpp"

using namespace Microsoft::Quantum;
using namespace std;

extern "C" void Hello__HelloQ();

int main(int argc, char* argv[]){
unique_ptr<IRuntimeDriver> sim = CreateFullstateSimulator();
QirContextScope qirctx(sim.get(), true /*trackAllocatedObjects*/);
Hello__HelloQ();
return 0;
}

0 comments on commit 35ac6ce

Please sign in to comment.