diff --git a/.github/workflows/automerge.yml b/.github/workflows/automerge.yml deleted file mode 100644 index 143313aa57e..00000000000 --- a/.github/workflows/automerge.yml +++ /dev/null @@ -1,38 +0,0 @@ -# This action allows using the automerge label to automatically merge in pull requests that have been reviewed and that pass -# status checks (similar to the autocomplete functionality of Azure DevOps). -name: automerge -on: - pull_request: - # Note that we only support automerge on branches that have required checks. - branches: - - main - - feature/* - types: - - labeled - - unlabeled - - synchronize - - opened - - edited - - ready_for_review - - reopened - - unlocked - pull_request_review: - # Note that we only support automerge on branches that have required checks. - branches: - - main - - feature/* - types: - - submitted - check_suite: - types: - - completed - status: {} -jobs: - automerge: - runs-on: ubuntu-latest - steps: - - name: automerge - uses: "pascalgn/automerge-action@4536e8847eb62fe2f0ee52c8fa92d17aa97f932f" - env: - GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" - MERGE_METHOD: squash diff --git a/.gitignore b/.gitignore index f77b7e72b01..5b33b48524e 100644 --- a/.gitignore +++ b/.gitignore @@ -24,7 +24,7 @@ bld/ [Oo]bj/ [Ll]og/ [Dd]rops/ -**/qir-gen.ll +[Dd]ocs/ # Visual Studio 2015/2017 cache/options directory .vs/ diff --git a/AdvantageBenchmark/privateBuild/host.csproj b/AdvantageBenchmark/privateBuild/host.csproj index 422cd590f67..f6576ae8481 100644 --- a/AdvantageBenchmark/privateBuild/host.csproj +++ b/AdvantageBenchmark/privateBuild/host.csproj @@ -1,4 +1,4 @@ - + diff --git a/AdvantageBenchmark/releasedBuild/quantum/quantum.csproj b/AdvantageBenchmark/releasedBuild/quantum/quantum.csproj index 50c82fa9032..aa2a2ab5f59 100644 --- a/AdvantageBenchmark/releasedBuild/quantum/quantum.csproj +++ b/AdvantageBenchmark/releasedBuild/quantum/quantum.csproj @@ -1,4 +1,4 @@ - + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f0dc1941d60..16cecebf8a9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,7 +3,7 @@ Welcome, and thank you for your interest in contributing to Q#! There are many ways in which you can contribute, beyond writing code. The goal of this document is to provide a high-level overview of how you can get involved. -For more details on how to contribute to Q# or the rest of the Quantum Development Kit, please see the [contribution guide](https://docs.microsoft.com/quantum/contributing/). +For more details on how to contribute to Q# or the rest of the Quantum Development Kit, please see the [contribution guide](https://docs.microsoft.com/azure/quantum/contributing-overview). ## Asking Questions @@ -18,7 +18,7 @@ Have a feature request? We want to hear about it! Here's how you can make reporting your issue as effective as possible. -The Quantum Development Kit is distributed across multiple repositories. Filing an issue against the correct repository will help address it swiftly. Check the list [in the contribution guide](https://docs.microsoft.com/quantum/contributing/#where-do-contributions-go) to figure out which repo is a good place to file it. +The Quantum Development Kit is distributed across multiple repositories. Filing an issue against the correct repository will help address it swiftly. Check the list [in the contribution guide](https://docs.microsoft.com/azure/quantum/contributing-overview#where-do-contributions-go) to figure out which repo is a good place to file it. You can follow the [template](https://github.com/microsoft/qsharp-runtime/issues/new?assignees=&labels=bug&template=bug_report.md&title=) for reporting issues on this repository. @@ -43,7 +43,7 @@ please file one following the [feature request template](https://github.com/micr We will respond to feature requests and follow up with a discussion around its feasibility, how one might go about implementing it, and whether that is something we would consider adding to our repo. There are several reasons why we might not be able to eventually merge even a great feature for one reason or another. -Take a look at our general contribution guide for [reasons why this might be the case](https://docs.microsoft.com/quantum/contributing/code#when-well-reject-a-pull-request). +Take a look at our general contribution guide for [reasons why this might be the case](https://docs.microsoft.com/azure/quantum/contributing-code#when-well-reject-a-pull-request). Even if we are not able to incorporate something into the packages and extensions we distribute, we encourage you to pursue your passion project in your own fork, and share and discuss your thoughts and progress on the corresponding issue. @@ -53,12 +53,12 @@ search for example for the [good-first-issue](https://github.com/microsoft/qshar Also, look for issues that have already been discussed in more detail, and check if you can help someone who has already started working on it. -Whether you want to help fixing bugs or add new features, please take a look at our general guide for [Contributing Code](https://docs.microsoft.com/quantum/contributing/code). +Whether you want to help fixing bugs or add new features, please take a look at our general guide for [Contributing Code](https://docs.microsoft.com/azure/quantum/contributing-code). ## Contributing Documentation If you are interested in contributing to conceptual documentation about Q#, please see the [MicrosoftDocs/quantum-docs-pr](https://github.com/MicrosoftDocs/quantum-docs-pr) repository. -If you are interested in contributing API references, please see [Contributing Code](https://docs.microsoft.com/quantum/contributing/code) in the contribution guide. +If you are interested in contributing API references, please see [Contributing Code](https://docs.microsoft.com/azure/quantum/contributing-code) in the contribution guide. And last but not least: diff --git a/README.md b/README.md index 61905922d77..7554ea9ab78 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Welcome to the Microsoft Quantum Development Kit! -This repository contains the runtime components for the [Quantum Development Kit](https://docs.microsoft.com/quantum/). +This repository contains the runtime components for the [Quantum Development Kit](https://docs.microsoft.com/azure/quantum/). It consists of the libraries and packages needed to create and simulate quantum applications using Q#. - **[Azure/](./src/Azure/)**: Source for client package to create and manage jobs in Azure Quantum. @@ -11,14 +11,14 @@ It consists of the libraries and packages needed to create and simulate quantum ## New to Quantum? ## -See the [introduction to quantum computing](https://docs.microsoft.com/quantum/concepts/) provided with the Quantum Development Kit. +See the [introduction to quantum computing](https://docs.microsoft.com/azure/quantum/concepts-overview) provided with the Quantum Development Kit. ## Installing the Quantum Development Kit -**If you're looking to use Q# to write quantum applications, please see the instructions on how to get started with using the [Quantum Development Kit](https://docs.microsoft.com/quantum/install-guide/) including the Q# compiler, language server, and development environment extensions.** +**If you're looking to use Q# to write quantum applications, please see the instructions on how to get started with using the [Quantum Development Kit](https://docs.microsoft.com/azure/quantum/install-overview-qdk) including the Q# compiler, language server, and development environment extensions.** -Please see the [installation guide](https://docs.microsoft.com/quantum/install-guide) for further information on how to get started using the Quantum Development Kit to develop quantum applications. +Please see the [installation guide](https://docs.microsoft.com/azure/quantum/install-overview-qdk) for further information on how to get started using the Quantum Development Kit to develop quantum applications. You may also visit our [Quantum](https://github.com/microsoft/quantum) repository, which offers a wide variety of samples on how to write quantum based programs. @@ -28,7 +28,7 @@ You may also visit our [Quantum](https://github.com/microsoft/quantum) repositor Note that when building from source, this repository is configured so that .NET Core will automatically look at the [Quantum Development Kit prerelease feed](https://dev.azure.com/ms-quantum-public/Microsoft%20Quantum%20(public)/_packaging?_a=feed&feed=alpha) in addition to any other feeds you may have configured. -Building **QIR Runtime** isn't enabled by default yet. Please see [its readme](./src/QirRuntime/README.md) for details. +Building **QIR Runtime** isn't enabled by default yet. Please see [its readme](./src/Qir/Runtime/README.md) for details. ### Windows ### @@ -57,6 +57,28 @@ To build on other platforms: 1. Install the pre-reqs: * Install [CMake](https://cmake.org/install/) * Install [.NET Core 3 SDK](https://dotnet.microsoft.com/download) + * On [WSL](https://docs.microsoft.com/en-us/windows/wsl/)/Linux: + * Install `g++` (e.g. in Ubuntu 20.04 `sudo apt-get install g++`). + * The build does not accept `dotnet-*-5.0` packages, install `dotnet-*-3.1` + (`sudo apt-get install dotnet-sdk-3.1`). The possible result can be: + +```sh +qsharp-runtime$ dpkg -l *dotnet* +Desired=Unknown/Install/Remove/Purge/Hold +| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend +|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad) +||/ Name Version Architecture Description ++++-=========================-============-============-================================================================= +un dotnet (no description available) +ii dotnet-apphost-pack-3.1 3.1.13-1 amd64 Microsoft.NETCore.App.Host 3.1.13 +ii dotnet-host 5.0.4-1 amd64 Microsoft .NET Host - 5.0.4 +ii dotnet-hostfxr-3.1 3.1.13-1 amd64 Microsoft .NET Core Host FX Resolver - 3.1.13 3.1.13 +un dotnet-nightly (no description available) +ii dotnet-runtime-3.1 3.1.13-1 amd64 Microsoft .NET Core Runtime - 3.1.13 Microsoft.NETCore.App 3.1.13 +ii dotnet-runtime-deps-3.1 3.1.13-1 amd64 dotnet-runtime-deps-3.1 3.1.13 +ii dotnet-sdk-3.1 3.1.407-1 amd64 Microsoft .NET Core SDK 3.1.407 +ii dotnet-targeting-pack-3.1 3.1.0-1 amd64 Microsoft.NETCore.App.Ref 3.1.0 +``` 2. Run [bootstrap.ps1](./bootstrap.ps1) * The script might install additional tools (a specific compiler, build tools, etc) * Then it builds release flavor of the native (C++) full-state simulator and debug flavor of the Simulation solution. @@ -81,7 +103,7 @@ All unit tests are part of the `Simulation.sln` solution. To run the tests: ## Feedback ## If you have feedback about the Q# simulators or any other runtime component, please let us know by filing a [new issue](https://github.com/microsoft/qsharp-runtime/issues/new)! -If you have feedback about some other part of the Microsoft Quantum Development Kit, please see the [contribution guide](https://docs.microsoft.com/quantum/contributing/) for more information. +If you have feedback about some other part of the Microsoft Quantum Development Kit, please see the [contribution guide](https://docs.microsoft.com/azure/quantum/contributing-overview) for more information. ## Reporting Security Issues @@ -111,4 +133,4 @@ This project has adopted the [Microsoft Open Source Code of Conduct](https://ope For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. -For more details, please see [CONTRIBUTING.md](./CONTRIBUTING.md), or the [contribution guide](https://docs.microsoft.com/quantum/contributing/). +For more details, please see [CONTRIBUTING.md](./CONTRIBUTING.md), or the [contribution guide](https://docs.microsoft.com/azure/quantum/contributing-overview). diff --git a/Simulation.sln b/Simulation.sln index b13975b999a..9a65f34a9db 100644 --- a/Simulation.sln +++ b/Simulation.sln @@ -63,7 +63,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IonQExe", "src\Simulation\S EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QCIExe", "src\Simulation\Simulators.Tests\TestProjects\QCIExe\QCIExe.csproj", "{C015FF41-9A51-4AF0-AEFC-2547D596B10A}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TargetedExe", "src\Simulation\Simulators.Tests\TestProjects\TargetedExe\TargetedExe.csproj", "{D292BF18-3956-4827-820E-254C3F81EF09}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TargetedExe", "src\Simulation\Simulators.Tests\TestProjects\TargetedExe\TargetedExe.csproj", "{D292BF18-3956-4827-820E-254C3F81EF09}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Quantum.QSharp.Foundation", "src\Simulation\QSharpFoundation\Microsoft.Quantum.QSharp.Foundation.csproj", "{DB45AD73-4D91-43F3-85CC-C63614A96FB0}" EndProject @@ -71,7 +71,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Quantum.Type2.Cor EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests.Microsoft.Quantum.Simulators.Type2", "src\Simulation\Simulators.Type2.Tests\Tests.Microsoft.Quantum.Simulators.Type2.csproj", "{ED3D7040-4B3F-4217-A75E-9DF63DD84707}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IntrinsicTests", "src\Simulation\Simulators.Tests\TestProjects\IntrinsicTests\IntrinsicTests.csproj", "{4EF958CA-B4A6-4E5F-924A-100B5615BEC3}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IntrinsicTests", "src\Simulation\Simulators.Tests\TestProjects\IntrinsicTests\IntrinsicTests.csproj", "{4EF958CA-B4A6-4E5F-924A-100B5615BEC3}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests.Microsoft.Quantum.Simulators.Type1", "src\Simulation\Simulators.Type1.Tests\Tests.Microsoft.Quantum.Simulators.Type1.csproj", "{EB6E3DBD-C884-4241-9BC4-8281191D1F53}" EndProject @@ -85,6 +85,34 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Quantum.Type3.Cor EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests.Microsoft.Quantum.Simulators.Type3", "src\Simulation\Simulators.Type3.Tests\Tests.Microsoft.Quantum.Simulators.Type3.csproj", "{7F80466B-A6B5-4EF1-A9E9-22ABAE3C20C1}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{020356B7-C3FC-4100-AE37-97E5D8288D1D}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Qir", "Qir", "{F6C2D4C0-12DC-40E3-9C86-FA5308D9B567}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{7F7BB60A-5DCB-469E-8546-1BE9E3CAC833}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "FullstateSimulator", "FullstateSimulator", "{EAC5EAE7-D1B3-4726-AFDB-73000E62176A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "qir-test-simulator", "src\Qir\Tests\FullstateSimulator\qsharp\qir-test-simulator.csproj", "{C7531119-9730-497A-9D11-8BBB3761B726}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "QIR-dynamic", "QIR-dynamic", "{3DFACF7F-D5C2-455B-AB8A-26908DEF7E2D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "qir-test-random", "src\Qir\Tests\QIR-dynamic\qsharp\qir-test-random.csproj", "{5DBF6402-D9CD-4470-A309-3755CFDA42CF}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "QIR-static", "QIR-static", "{54000816-122C-4AA0-9FE9-B0ABB9547232}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "qir-gen", "src\Qir\Tests\QIR-static\qsharp\qir-gen.csproj", "{33ED37AB-61B1-4A49-9952-58D19AA8EF30}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "QIR-tracer", "QIR-tracer", "{522EAA31-6317-42D5-831F-C39313DF03A0}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "tracer-qir", "src\Qir\Tests\QIR-tracer\qsharp\tracer-qir.csproj", "{002174F4-BFA8-4675-908D-0E9C32ED951A}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{AAFB81D3-BC87-404D-BA64-AF40B2D2E45A}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "StandaloneInputReference", "StandaloneInputReference", "{A7DB7367-9FD6-4164-8263-A05077BE54AB}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "qir-standalone-input-reference", "src\Qir\Samples\StandaloneInputReference\qsharp\qir-standalone-input-reference.csproj", "{D7D34736-A719-4B45-A33F-2723F59EC29D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -641,6 +669,86 @@ Global {7F80466B-A6B5-4EF1-A9E9-22ABAE3C20C1}.RelWithDebInfo|Any CPU.Build.0 = Debug|Any CPU {7F80466B-A6B5-4EF1-A9E9-22ABAE3C20C1}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU {7F80466B-A6B5-4EF1-A9E9-22ABAE3C20C1}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU + {C7531119-9730-497A-9D11-8BBB3761B726}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C7531119-9730-497A-9D11-8BBB3761B726}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C7531119-9730-497A-9D11-8BBB3761B726}.Debug|x64.ActiveCfg = Debug|Any CPU + {C7531119-9730-497A-9D11-8BBB3761B726}.Debug|x64.Build.0 = Debug|Any CPU + {C7531119-9730-497A-9D11-8BBB3761B726}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU + {C7531119-9730-497A-9D11-8BBB3761B726}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU + {C7531119-9730-497A-9D11-8BBB3761B726}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU + {C7531119-9730-497A-9D11-8BBB3761B726}.MinSizeRel|x64.Build.0 = Debug|Any CPU + {C7531119-9730-497A-9D11-8BBB3761B726}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C7531119-9730-497A-9D11-8BBB3761B726}.Release|Any CPU.Build.0 = Release|Any CPU + {C7531119-9730-497A-9D11-8BBB3761B726}.Release|x64.ActiveCfg = Release|Any CPU + {C7531119-9730-497A-9D11-8BBB3761B726}.Release|x64.Build.0 = Release|Any CPU + {C7531119-9730-497A-9D11-8BBB3761B726}.RelWithDebInfo|Any CPU.ActiveCfg = Debug|Any CPU + {C7531119-9730-497A-9D11-8BBB3761B726}.RelWithDebInfo|Any CPU.Build.0 = Debug|Any CPU + {C7531119-9730-497A-9D11-8BBB3761B726}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU + {C7531119-9730-497A-9D11-8BBB3761B726}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU + {5DBF6402-D9CD-4470-A309-3755CFDA42CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5DBF6402-D9CD-4470-A309-3755CFDA42CF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5DBF6402-D9CD-4470-A309-3755CFDA42CF}.Debug|x64.ActiveCfg = Debug|Any CPU + {5DBF6402-D9CD-4470-A309-3755CFDA42CF}.Debug|x64.Build.0 = Debug|Any CPU + {5DBF6402-D9CD-4470-A309-3755CFDA42CF}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU + {5DBF6402-D9CD-4470-A309-3755CFDA42CF}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU + {5DBF6402-D9CD-4470-A309-3755CFDA42CF}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU + {5DBF6402-D9CD-4470-A309-3755CFDA42CF}.MinSizeRel|x64.Build.0 = Debug|Any CPU + {5DBF6402-D9CD-4470-A309-3755CFDA42CF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5DBF6402-D9CD-4470-A309-3755CFDA42CF}.Release|Any CPU.Build.0 = Release|Any CPU + {5DBF6402-D9CD-4470-A309-3755CFDA42CF}.Release|x64.ActiveCfg = Release|Any CPU + {5DBF6402-D9CD-4470-A309-3755CFDA42CF}.Release|x64.Build.0 = Release|Any CPU + {5DBF6402-D9CD-4470-A309-3755CFDA42CF}.RelWithDebInfo|Any CPU.ActiveCfg = Debug|Any CPU + {5DBF6402-D9CD-4470-A309-3755CFDA42CF}.RelWithDebInfo|Any CPU.Build.0 = Debug|Any CPU + {5DBF6402-D9CD-4470-A309-3755CFDA42CF}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU + {5DBF6402-D9CD-4470-A309-3755CFDA42CF}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU + {33ED37AB-61B1-4A49-9952-58D19AA8EF30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {33ED37AB-61B1-4A49-9952-58D19AA8EF30}.Debug|Any CPU.Build.0 = Debug|Any CPU + {33ED37AB-61B1-4A49-9952-58D19AA8EF30}.Debug|x64.ActiveCfg = Debug|Any CPU + {33ED37AB-61B1-4A49-9952-58D19AA8EF30}.Debug|x64.Build.0 = Debug|Any CPU + {33ED37AB-61B1-4A49-9952-58D19AA8EF30}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU + {33ED37AB-61B1-4A49-9952-58D19AA8EF30}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU + {33ED37AB-61B1-4A49-9952-58D19AA8EF30}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU + {33ED37AB-61B1-4A49-9952-58D19AA8EF30}.MinSizeRel|x64.Build.0 = Debug|Any CPU + {33ED37AB-61B1-4A49-9952-58D19AA8EF30}.Release|Any CPU.ActiveCfg = Release|Any CPU + {33ED37AB-61B1-4A49-9952-58D19AA8EF30}.Release|Any CPU.Build.0 = Release|Any CPU + {33ED37AB-61B1-4A49-9952-58D19AA8EF30}.Release|x64.ActiveCfg = Release|Any CPU + {33ED37AB-61B1-4A49-9952-58D19AA8EF30}.Release|x64.Build.0 = Release|Any CPU + {33ED37AB-61B1-4A49-9952-58D19AA8EF30}.RelWithDebInfo|Any CPU.ActiveCfg = Debug|Any CPU + {33ED37AB-61B1-4A49-9952-58D19AA8EF30}.RelWithDebInfo|Any CPU.Build.0 = Debug|Any CPU + {33ED37AB-61B1-4A49-9952-58D19AA8EF30}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU + {33ED37AB-61B1-4A49-9952-58D19AA8EF30}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU + {002174F4-BFA8-4675-908D-0E9C32ED951A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {002174F4-BFA8-4675-908D-0E9C32ED951A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {002174F4-BFA8-4675-908D-0E9C32ED951A}.Debug|x64.ActiveCfg = Debug|Any CPU + {002174F4-BFA8-4675-908D-0E9C32ED951A}.Debug|x64.Build.0 = Debug|Any CPU + {002174F4-BFA8-4675-908D-0E9C32ED951A}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU + {002174F4-BFA8-4675-908D-0E9C32ED951A}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU + {002174F4-BFA8-4675-908D-0E9C32ED951A}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU + {002174F4-BFA8-4675-908D-0E9C32ED951A}.MinSizeRel|x64.Build.0 = Debug|Any CPU + {002174F4-BFA8-4675-908D-0E9C32ED951A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {002174F4-BFA8-4675-908D-0E9C32ED951A}.Release|Any CPU.Build.0 = Release|Any CPU + {002174F4-BFA8-4675-908D-0E9C32ED951A}.Release|x64.ActiveCfg = Release|Any CPU + {002174F4-BFA8-4675-908D-0E9C32ED951A}.Release|x64.Build.0 = Release|Any CPU + {002174F4-BFA8-4675-908D-0E9C32ED951A}.RelWithDebInfo|Any CPU.ActiveCfg = Debug|Any CPU + {002174F4-BFA8-4675-908D-0E9C32ED951A}.RelWithDebInfo|Any CPU.Build.0 = Debug|Any CPU + {002174F4-BFA8-4675-908D-0E9C32ED951A}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU + {002174F4-BFA8-4675-908D-0E9C32ED951A}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU + {D7D34736-A719-4B45-A33F-2723F59EC29D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D7D34736-A719-4B45-A33F-2723F59EC29D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D7D34736-A719-4B45-A33F-2723F59EC29D}.Debug|x64.ActiveCfg = Debug|Any CPU + {D7D34736-A719-4B45-A33F-2723F59EC29D}.Debug|x64.Build.0 = Debug|Any CPU + {D7D34736-A719-4B45-A33F-2723F59EC29D}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU + {D7D34736-A719-4B45-A33F-2723F59EC29D}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU + {D7D34736-A719-4B45-A33F-2723F59EC29D}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU + {D7D34736-A719-4B45-A33F-2723F59EC29D}.MinSizeRel|x64.Build.0 = Debug|Any CPU + {D7D34736-A719-4B45-A33F-2723F59EC29D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D7D34736-A719-4B45-A33F-2723F59EC29D}.Release|Any CPU.Build.0 = Release|Any CPU + {D7D34736-A719-4B45-A33F-2723F59EC29D}.Release|x64.ActiveCfg = Release|Any CPU + {D7D34736-A719-4B45-A33F-2723F59EC29D}.Release|x64.Build.0 = Release|Any CPU + {D7D34736-A719-4B45-A33F-2723F59EC29D}.RelWithDebInfo|Any CPU.ActiveCfg = Debug|Any CPU + {D7D34736-A719-4B45-A33F-2723F59EC29D}.RelWithDebInfo|Any CPU.Build.0 = Debug|Any CPU + {D7D34736-A719-4B45-A33F-2723F59EC29D}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU + {D7D34736-A719-4B45-A33F-2723F59EC29D}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -681,8 +789,21 @@ Global {789C86D9-CE77-40DA-BDDD-979436952512} = {93409CC3-8DF9-45FA-AE21-16A19FDEF650} {7E24885B-D86D-477E-A840-06FA53C33FE1} = {34D419E9-CCF1-4E48-9FA4-3AD4B86BEEB4} {7F80466B-A6B5-4EF1-A9E9-22ABAE3C20C1} = {34D419E9-CCF1-4E48-9FA4-3AD4B86BEEB4} + {F6C2D4C0-12DC-40E3-9C86-FA5308D9B567} = {020356B7-C3FC-4100-AE37-97E5D8288D1D} + {7F7BB60A-5DCB-469E-8546-1BE9E3CAC833} = {F6C2D4C0-12DC-40E3-9C86-FA5308D9B567} + {EAC5EAE7-D1B3-4726-AFDB-73000E62176A} = {7F7BB60A-5DCB-469E-8546-1BE9E3CAC833} + {C7531119-9730-497A-9D11-8BBB3761B726} = {EAC5EAE7-D1B3-4726-AFDB-73000E62176A} + {3DFACF7F-D5C2-455B-AB8A-26908DEF7E2D} = {7F7BB60A-5DCB-469E-8546-1BE9E3CAC833} + {5DBF6402-D9CD-4470-A309-3755CFDA42CF} = {3DFACF7F-D5C2-455B-AB8A-26908DEF7E2D} + {54000816-122C-4AA0-9FE9-B0ABB9547232} = {7F7BB60A-5DCB-469E-8546-1BE9E3CAC833} + {33ED37AB-61B1-4A49-9952-58D19AA8EF30} = {54000816-122C-4AA0-9FE9-B0ABB9547232} + {522EAA31-6317-42D5-831F-C39313DF03A0} = {7F7BB60A-5DCB-469E-8546-1BE9E3CAC833} + {002174F4-BFA8-4675-908D-0E9C32ED951A} = {522EAA31-6317-42D5-831F-C39313DF03A0} + {AAFB81D3-BC87-404D-BA64-AF40B2D2E45A} = {F6C2D4C0-12DC-40E3-9C86-FA5308D9B567} + {A7DB7367-9FD6-4164-8263-A05077BE54AB} = {AAFB81D3-BC87-404D-BA64-AF40B2D2E45A} + {D7D34736-A719-4B45-A33F-2723F59EC29D} = {A7DB7367-9FD6-4164-8263-A05077BE54AB} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {929C0464-86D8-4F70-8835-0A5EAF930821} EndGlobalSection -EndGlobal \ No newline at end of file +EndGlobal diff --git a/bootstrap.ps1 b/bootstrap.ps1 index 15982134618..7ad031ef42d 100644 --- a/bootstrap.ps1 +++ b/bootstrap.ps1 @@ -7,14 +7,6 @@ Push-Location (Join-Path $PSScriptRoot "build") .\prerequisites.ps1 Pop-Location -# Temporary hack until switch qdk build pipeline to use the new build scripts (as a result it will build the native -# simulator twice, but the second build should be mostly noop) -if (($Env:CI -eq $null) -and ($Env:ENABLE_NATIVE -ne "false")) { - Push-Location (Join-Path $PSScriptRoot "src/Simulation/Native") - .\build-native-simulator.ps1 - Pop-Location -} - if (-not (Test-Path Env:AGENT_OS)) { if ($Env:ENABLE_NATIVE -ne "false") { Write-Host "Build release flavor of the native simulator" @@ -22,6 +14,7 @@ if (-not (Test-Path Env:AGENT_OS)) { Push-Location (Join-Path $PSScriptRoot "src/Simulation/Native") .\build-native-simulator.ps1 Pop-Location + $Env:BUILD_CONFIGURATION = $null } Write-Host "Build simulation solution" diff --git a/build/build.ps1 b/build/build.ps1 index 9ff2e82b758..dec45cec756 100644 --- a/build/build.ps1 +++ b/build/build.ps1 @@ -16,6 +16,16 @@ if ($Env:ENABLE_NATIVE -ne "false") { Write-Host "Skipping build of native simulator because ENABLE_NATIVE variable is set to: $Env:ENABLE_NATIVE." } +if ($Env:ENABLE_QIRRUNTIME -ne "false") { + $qirRuntime = (Join-Path $PSScriptRoot "../src/Qir/Runtime") + & "$qirRuntime/build-qir-runtime.ps1" + if ($LastExitCode -ne 0) { + $script:all_ok = $False + } +} else { + Write-Host "Skipping build of qir runtime because ENABLE_QIRRUNTIME variable is set to: $Env:ENABLE_QIRRUNTIME" +} + function Build-One { param( [string]$action, @@ -45,14 +55,19 @@ Build-One 'publish' '../src/Simulation/CSharpGeneration.App' Build-One 'build' '../Simulation.sln' -if ($Env:ENABLE_QIRRUNTIME -eq "true") { - $qirRuntime = (Join-Path $PSScriptRoot "../src/QirRuntime") - & "$qirRuntime/build-qir-runtime.ps1" +if ($Env:ENABLE_QIRRUNTIME -ne "false") { + $qirTests = (Join-Path $PSScriptRoot "../src/Qir/Tests") + & "$qirTests/build-qir-tests.ps1" -SkipQSharpBuild + if ($LastExitCode -ne 0) { + $script:all_ok = $False + } + $qirSamples = (Join-Path $PSScriptRoot "../src/Qir/Samples") + & "$qirSamples/build-qir-samples.ps1" -SkipQSharpBuild if ($LastExitCode -ne 0) { $script:all_ok = $False } } else { - Write-Host "Skipping build of qir runtime because ENABLE_QIRRUNTIME variable is set to: $Env:ENABLE_QIRRUNTIME" + Write-Host "Skipping build of qir tests because ENABLE_QIRRUNTIME variable is set to: $Env:ENABLE_QIRRUNTIME" } if (-not $all_ok) { diff --git a/build/ci.yml b/build/ci.yml index 111b68c0595..34383b7c24f 100644 --- a/build/ci.yml +++ b/build/ci.yml @@ -22,7 +22,6 @@ variables: Drops.Dir: $(Build.ArtifactStagingDirectory)/drops Drop.Native: $(System.DefaultWorkingDirectory)/xplat CI: "true" - ENABLE_QIRRUNTIME: "false" jobs: - job: build diff --git a/build/manifest.ps1 b/build/manifest.ps1 index 177c66f10e3..ac2821339bb 100644 --- a/build/manifest.ps1 +++ b/build/manifest.ps1 @@ -26,6 +26,8 @@ $artifacts = @{ "Microsoft.Quantum.QSharp.Core", "Microsoft.Quantum.Type1.Core", "Microsoft.Quantum.Type2.Core", + "Microsoft.Quantum.Type3.Core", + "Microsoft.Quantum.QSharp.Foundation" "Microsoft.Quantum.Runtime.Core", "Microsoft.Quantum.Simulators", "Microsoft.Quantum.Xunit" @@ -41,6 +43,7 @@ $artifacts = @{ ".\src\Simulation\QSharpCore\bin\$Env:BUILD_CONFIGURATION\netstandard2.1\Microsoft.Quantum.QSharp.Core.dll", ".\src\Simulation\Type1Core\bin\$Env:BUILD_CONFIGURATION\netstandard2.1\Microsoft.Quantum.Type1.Core.dll", ".\src\Simulation\Type2Core\bin\$Env:BUILD_CONFIGURATION\netstandard2.1\Microsoft.Quantum.Type2.Core.dll", + ".\src\Simulation\Type3Core\bin\$Env:BUILD_CONFIGURATION\netstandard2.1\Microsoft.Quantum.Type3.Core.dll", ".\src\Simulation\QSharpFoundation\bin\$Env:BUILD_CONFIGURATION\netstandard2.1\Microsoft.Quantum.QSharp.Foundation.dll", ".\src\Simulation\Simulators\bin\$Env:BUILD_CONFIGURATION\netstandard2.1\Microsoft.Quantum.Simulation.Common.dll", ".\src\Simulation\Simulators\bin\$Env:BUILD_CONFIGURATION\netstandard2.1\Microsoft.Quantum.Simulation.QCTraceSimulatorRuntime.dll", @@ -49,7 +52,11 @@ $artifacts = @{ ) | ForEach-Object { Join-Path $PSScriptRoot (Join-Path ".." $_) }; Native = @( - ".\src\Simulation\Simulators\bin\$Env:BUILD_CONFIGURATION\netstandard2.1\Microsoft.Quantum.Simulator.Runtime.dll" + ".\src\Simulation\Simulators\bin\$Env:BUILD_CONFIGURATION\netstandard2.1\Microsoft.Quantum.Simulator.Runtime.dll", + ".\src\Qir\Runtime\build\$Env:BUILD_CONFIGURATION\bin\Microsoft.Quantum.Qir.QSharp.Core.dll", + ".\src\Qir\Runtime\build\$Env:BUILD_CONFIGURATION\bin\Microsoft.Quantum.Qir.QSharp.Foundation.dll", + ".\src\Qir\Runtime\build\$Env:BUILD_CONFIGURATION\bin\Microsoft.Quantum.Qir.Runtime.dll", + ".\src\Qir\Runtime\build\$Env:BUILD_CONFIGURATION\bin\Microsoft.Quantum.Qir.Tracer.dll" ) | ForEach-Object { Join-Path $PSScriptRoot (Join-Path ".." $_) }; } diff --git a/build/prerequisites.ps1 b/build/prerequisites.ps1 index 2d745543ecf..c5176286e67 100644 --- a/build/prerequisites.ps1 +++ b/build/prerequisites.ps1 @@ -21,12 +21,6 @@ if ($Env:ENABLE_NATIVE -ne "false") { Write-Host "Skipping installing prerequisites for native simulator because ENABLE_NATIVE variable set to: $Env:ENABLE_NATIVE" } -# At the moment the QIR Runtime build isn't enabled locally by default. -if ($Env:ENABLE_QIRRUNTIME -eq "true") { - Push-Location (Join-Path $PSScriptRoot "../src/QirRuntime") - .\prerequisites.ps1 - Pop-Location -} else { - Write-Host "Skipping installing prerequisites for qir runtime because ENABLE_QIRRUNTIME variable set to: $Env:ENABLE_QIRRUNTIME" -} - +Push-Location (Join-Path $PSScriptRoot "../src/Qir/Runtime") + .\prerequisites.ps1 +Pop-Location diff --git a/build/test.ps1 b/build/test.ps1 index cc2e0507a28..974c2a61615 100644 --- a/build/test.ps1 +++ b/build/test.ps1 @@ -37,15 +37,24 @@ function Test-One { Test-One '../Simulation.sln' -if (($Env:ENABLE_NATIVE -ne "false") -and ($Env:ENABLE_QIRRUNTIME -eq "true")) { - $qirRuntime = (Join-Path $PSScriptRoot "../src/QirRuntime") +if ($Env:ENABLE_QIRRUNTIME -ne "false") { + $qirRuntime = (Join-Path $PSScriptRoot "../src/Qir/Runtime") & "$qirRuntime/test-qir-runtime.ps1" if ($LastExitCode -ne 0) { $script:all_ok = $False } + $qirTests = (Join-Path $PSScriptRoot "../src/Qir/Tests") + & "$qirTests/test-qir-tests.ps1" + if ($LastExitCode -ne 0) { + $script:all_ok = $False + } + $qirSamples = (Join-Path $PSScriptRoot "../src/Qir/Samples") + & "$qirSamples/test-qir-samples.ps1" + if ($LastExitCode -ne 0) { + $script:all_ok = $False + } } else { - Write-Host "Skipping test of qir runtime because ENABLE_QIRRUNTIME variable is set to: $Env:ENABLE_QIRRUNTIME ` - and ENABLE_NATIVE variable is set to: $Env:ENABLE_NATIVE." + Write-Host "Skipping test of qir runtime because ENABLE_QIRRUNTIME variable is set to: $Env:ENABLE_QIRRUNTIME." } if (-not $all_ok) { diff --git a/global.json b/global.json new file mode 100644 index 00000000000..b61664f8c47 --- /dev/null +++ b/global.json @@ -0,0 +1,5 @@ +{ + "msbuild-sdks": { + "Microsoft.Quantum.Sdk": "0.15.210325056-pull" + } +} diff --git a/src/Azure/Azure.Quantum.Client/Microsoft.Azure.Quantum.Client.csproj b/src/Azure/Azure.Quantum.Client/Microsoft.Azure.Quantum.Client.csproj index 0b58a8e9699..444751e9078 100644 --- a/src/Azure/Azure.Quantum.Client/Microsoft.Azure.Quantum.Client.csproj +++ b/src/Azure/Azure.Quantum.Client/Microsoft.Azure.Quantum.Client.csproj @@ -9,8 +9,8 @@ - https://docs.microsoft.com/quantum/ - See: https://docs.microsoft.com/quantum/relnotes/ + https://docs.microsoft.com/azure/quantum/ + See: https://docs.microsoft.com/azure/quantum/qdk-relnotes/ MIT https://github.com/microsoft/qsharp-runtime Azure Quantum Q# QSharp @@ -20,7 +20,6 @@ - diff --git a/src/QirRuntime/.clang-format b/src/Qir/.clang-format similarity index 96% rename from src/QirRuntime/.clang-format rename to src/Qir/.clang-format index d5ac39db3de..34a87bcbbd9 100644 --- a/src/QirRuntime/.clang-format +++ b/src/Qir/.clang-format @@ -1,37 +1,37 @@ -# https://clang.llvm.org/docs/ClangFormatStyleOptions.html - ---- -Language: Cpp -BasedOnStyle: Microsoft - -# page width -ColumnLimit: 120 -ReflowComments: true - -# tabs and indents -UseTab: Never -IndentWidth: 4 -TabWidth: 4 -AccessModifierOffset: -2 -NamespaceIndentation: Inner - -# line and statements layout -BreakBeforeBraces: Allman -BinPackParameters: false -AlignAfterOpenBracket: AlwaysBreak -AllowShortIfStatementsOnASingleLine: WithoutElse -AllowShortFunctionsOnASingleLine: Empty -AllowAllConstructorInitializersOnNextLine: false -AllowAllArgumentsOnNextLine: true -AllowAllParametersOfDeclarationOnNextLine: false -BreakBeforeTernaryOperators: true -BreakConstructorInitializers: BeforeComma - -# misc -Cpp11BracedListStyle: true -FixNamespaceComments: true -IncludeBlocks: Preserve -SpaceBeforeInheritanceColon : true -SpaceBeforeParens: ControlStatements -DerivePointerAlignment: false -PointerAlignment: Left +# https://clang.llvm.org/docs/ClangFormatStyleOptions.html + +--- +Language: Cpp +BasedOnStyle: Microsoft + +# page width +ColumnLimit: 120 +ReflowComments: true + +# tabs and indents +UseTab: Never +IndentWidth: 4 +TabWidth: 4 +AccessModifierOffset: -2 +NamespaceIndentation: Inner + +# line and statements layout +BreakBeforeBraces: Allman +BinPackParameters: false +AlignAfterOpenBracket: AlwaysBreak +AllowShortIfStatementsOnASingleLine: WithoutElse +AllowShortFunctionsOnASingleLine: Empty +AllowAllConstructorInitializersOnNextLine: false +AllowAllArgumentsOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: false +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeComma + +# misc +Cpp11BracedListStyle: true +FixNamespaceComments: true +IncludeBlocks: Preserve +SpaceBeforeInheritanceColon : true +SpaceBeforeParens: ControlStatements +DerivePointerAlignment: false +PointerAlignment: Left diff --git a/src/QirRuntime/.clang-tidy b/src/Qir/.clang-tidy similarity index 97% rename from src/QirRuntime/.clang-tidy rename to src/Qir/.clang-tidy index 86a9dc17ad9..8fb71d1375a 100644 --- a/src/QirRuntime/.clang-tidy +++ b/src/Qir/.clang-tidy @@ -1,29 +1,29 @@ -Checks: - '-*,bugprone-*,-readability-*,readability-identifier-*,readability-braces-around-statements' -WarningsAsErrors: '*' -HeaderFilterRegex: '.*' - -CheckOptions: - - key: readability-identifier-naming.ClassCase - value: 'CamelCase' - - key: readability-identifier-naming.ClassPrefix - value: 'C' - - key: readability-identifier-naming.AbstractClassPrefix - value: 'I' - - key: readability-identifier-naming.StructCase - value: 'CamelCase' - - key: readability-identifier-naming.ParameterCase - value: 'camelBack' - - key: readability-identifier-naming.PrivateMemberCase - value: 'camelBack' - - key: readability-identifier-naming.LocalVariableCase - value: 'camelBack' - - key: readability-identifier-naming.TypeAliasCase - value: 'CamelCase' - - key: readability-identifier-naming.UnionCase - value: 'CamelCase' - - key: readability-identifier-naming.FunctionCase - value: 'CamelCase' - - key: readability-identifier-naming.NamespaceCase - value: 'CamelCase' - +Checks: + '-*,bugprone-*,-readability-*,readability-identifier-*,readability-braces-around-statements' +WarningsAsErrors: '*' +HeaderFilterRegex: '.*' + +CheckOptions: + - key: readability-identifier-naming.ClassCase + value: 'CamelCase' + - key: readability-identifier-naming.ClassPrefix + value: 'C' + - key: readability-identifier-naming.AbstractClassPrefix + value: 'I' + - key: readability-identifier-naming.StructCase + value: 'CamelCase' + - key: readability-identifier-naming.ParameterCase + value: 'camelBack' + - key: readability-identifier-naming.PrivateMemberCase + value: 'camelBack' + - key: readability-identifier-naming.LocalVariableCase + value: 'camelBack' + - key: readability-identifier-naming.TypeAliasCase + value: 'CamelCase' + - key: readability-identifier-naming.UnionCase + value: 'CamelCase' + - key: readability-identifier-naming.FunctionCase + value: 'CamelCase' + - key: readability-identifier-naming.NamespaceCase + value: 'CamelCase' + diff --git a/src/Qir/.gitignore b/src/Qir/.gitignore new file mode 100644 index 00000000000..44889a5d35b --- /dev/null +++ b/src/Qir/.gitignore @@ -0,0 +1,2 @@ +# Ignore the generated qir files from Q# compiler +qir/ diff --git a/src/QirRuntime/test/SimulatorStub.hpp b/src/Qir/Common/Include/SimulatorStub.hpp similarity index 59% rename from src/QirRuntime/test/SimulatorStub.hpp rename to src/Qir/Common/Include/SimulatorStub.hpp index 6f3d198f4e9..5a2a2459e9f 100644 --- a/src/QirRuntime/test/SimulatorStub.hpp +++ b/src/Qir/Common/Include/SimulatorStub.hpp @@ -1,139 +1,139 @@ -#pragma once - -#include - -#include "QirRuntimeApi_I.hpp" -#include "QSharpSimApi_I.hpp" - -namespace Microsoft -{ -namespace Quantum -{ - struct SimulatorStub : public IRuntimeDriver, public IQuantumGateSet - { - Qubit AllocateQubit() override - { - throw std::logic_error("not_implemented"); - } - void ReleaseQubit(Qubit qubit) override - { - throw std::logic_error("not_implemented"); - } - virtual std::string QubitToString(Qubit qubit) override - { - throw std::logic_error("not_implemented"); - } - void X(Qubit target) override - { - throw std::logic_error("not_implemented"); - } - void Y(Qubit target) override - { - throw std::logic_error("not_implemented"); - } - void Z(Qubit target) override - { - throw std::logic_error("not_implemented"); - } - void H(Qubit target) override - { - throw std::logic_error("not_implemented"); - } - void S(Qubit target) override - { - throw std::logic_error("not_implemented"); - } - void T(Qubit target) override - { - throw std::logic_error("not_implemented"); - } - void R(PauliId axis, Qubit target, double theta) override - { - throw std::logic_error("not_implemented"); - } - void Exp(long numTargets, PauliId paulis[], Qubit targets[], double theta) override - { - throw std::logic_error("not_implemented"); - } - void ControlledX(long numControls, Qubit controls[], Qubit target) override - { - throw std::logic_error("not_implemented"); - } - void ControlledY(long numControls, Qubit controls[], Qubit target) override - { - throw std::logic_error("not_implemented"); - } - void ControlledZ(long numControls, Qubit controls[], Qubit target) override - { - throw std::logic_error("not_implemented"); - } - void ControlledH(long numControls, Qubit controls[], Qubit target) override - { - throw std::logic_error("not_implemented"); - } - void ControlledS(long numControls, Qubit controls[], Qubit target) override - { - throw std::logic_error("not_implemented"); - } - void ControlledT(long numControls, Qubit controls[], Qubit target) override - { - throw std::logic_error("not_implemented"); - } - void ControlledR(long numControls, Qubit controls[], PauliId axis, Qubit target, double theta) override - { - throw std::logic_error("not_implemented"); - } - void ControlledExp( - long numControls, - Qubit controls[], - long numTargets, - PauliId paulis[], - Qubit targets[], - double theta) override - { - throw std::logic_error("not_implemented"); - } - void AdjointS(Qubit target) override - { - throw std::logic_error("not_implemented"); - } - void AdjointT(Qubit target) override - { - throw std::logic_error("not_implemented"); - } - void ControlledAdjointS(long numControls, Qubit controls[], Qubit target) override - { - throw std::logic_error("not_implemented"); - } - void ControlledAdjointT(long numControls, Qubit controls[], Qubit target) override - { - throw std::logic_error("not_implemented"); - } - Result Measure(long numBases, PauliId bases[], long numTargets, Qubit targets[]) override - { - throw std::logic_error("not_implemented"); - } - void ReleaseResult(Result result) override - { - throw std::logic_error("not_implemented"); - } - bool AreEqualResults(Result r1, Result r2) override - { - throw std::logic_error("not_implemented"); - } - ResultValue GetResultValue(Result result) override - { - throw std::logic_error("not_implemented"); - } - Result UseZero() override - { - throw std::logic_error("not_implemented"); - } - Result UseOne() override - { - throw std::logic_error("not_implemented"); - } - }; - -} // namespace Quantum +#pragma once + +#include + +#include "QirRuntimeApi_I.hpp" +#include "QSharpSimApi_I.hpp" + +namespace Microsoft +{ +namespace Quantum +{ + struct SimulatorStub : public IRuntimeDriver, public IQuantumGateSet + { + Qubit AllocateQubit() override + { + throw std::logic_error("not_implemented: AllocateQubit"); + } + void ReleaseQubit(Qubit qubit) override + { + throw std::logic_error("not_implemented: ReleaseQubit"); + } + virtual std::string QubitToString(Qubit qubit) override + { + throw std::logic_error("not_implemented: QubitToString"); + } + void X(Qubit target) override + { + throw std::logic_error("not_implemented: X"); + } + void Y(Qubit target) override + { + throw std::logic_error("not_implemented: Y"); + } + void Z(Qubit target) override + { + throw std::logic_error("not_implemented: Z"); + } + void H(Qubit target) override + { + throw std::logic_error("not_implemented: H"); + } + void S(Qubit target) override + { + throw std::logic_error("not_implemented: S"); + } + void T(Qubit target) override + { + throw std::logic_error("not_implemented: T"); + } + void R(PauliId axis, Qubit target, double theta) override + { + throw std::logic_error("not_implemented: R"); + } + void Exp(long numTargets, PauliId paulis[], Qubit targets[], double theta) override + { + throw std::logic_error("not_implemented: Exp"); + } + void ControlledX(long numControls, Qubit controls[], Qubit target) override + { + throw std::logic_error("not_implemented: ControlledX"); + } + void ControlledY(long numControls, Qubit controls[], Qubit target) override + { + throw std::logic_error("not_implemented: ControlledY"); + } + void ControlledZ(long numControls, Qubit controls[], Qubit target) override + { + throw std::logic_error("not_implemented: ControlledZ"); + } + void ControlledH(long numControls, Qubit controls[], Qubit target) override + { + throw std::logic_error("not_implemented: ControlledH"); + } + void ControlledS(long numControls, Qubit controls[], Qubit target) override + { + throw std::logic_error("not_implemented: ControlledS"); + } + void ControlledT(long numControls, Qubit controls[], Qubit target) override + { + throw std::logic_error("not_implemented: ControlledT"); + } + void ControlledR(long numControls, Qubit controls[], PauliId axis, Qubit target, double theta) override + { + throw std::logic_error("not_implemented: ControlledR"); + } + void ControlledExp( + long numControls, + Qubit controls[], + long numTargets, + PauliId paulis[], + Qubit targets[], + double theta) override + { + throw std::logic_error("not_implemented: ControlledExp"); + } + void AdjointS(Qubit target) override + { + throw std::logic_error("not_implemented: AdjointS"); + } + void AdjointT(Qubit target) override + { + throw std::logic_error("not_implemented: AdjointT"); + } + void ControlledAdjointS(long numControls, Qubit controls[], Qubit target) override + { + throw std::logic_error("not_implemented: ControlledAdjointS"); + } + void ControlledAdjointT(long numControls, Qubit controls[], Qubit target) override + { + throw std::logic_error("not_implemented: ControlledAdjointT"); + } + Result Measure(long numBases, PauliId bases[], long numTargets, Qubit targets[]) override + { + throw std::logic_error("not_implemented: Measure"); + } + void ReleaseResult(Result result) override + { + throw std::logic_error("not_implemented: ReleaseResult"); + } + bool AreEqualResults(Result r1, Result r2) override + { + throw std::logic_error("not_implemented: AreEqualResults"); + } + ResultValue GetResultValue(Result result) override + { + throw std::logic_error("not_implemented: GetResultValue"); + } + Result UseZero() override + { + throw std::logic_error("not_implemented: UseZero"); + } + Result UseOne() override + { + throw std::logic_error("not_implemented: UseOne"); + } + }; + +} // namespace Quantum } // namespace Microsoft \ No newline at end of file diff --git a/src/QirRuntime/lib/QSharpFoundation/qsharp__foundation_internal.hpp b/src/Qir/Common/Include/qsharp__foundation_internal.hpp similarity index 61% rename from src/QirRuntime/lib/QSharpFoundation/qsharp__foundation_internal.hpp rename to src/Qir/Common/Include/qsharp__foundation_internal.hpp index 6e923191efe..df2e844e5a1 100644 --- a/src/QirRuntime/lib/QSharpFoundation/qsharp__foundation_internal.hpp +++ b/src/Qir/Common/Include/qsharp__foundation_internal.hpp @@ -6,6 +6,8 @@ // To be included by the QIS implementation and QIS tests only. // Not to be included by parties outside QIS. +#include "CoreTypes.hpp" + // For test purposes only: namespace Quantum // Replace with `namespace Quantum::Qis::Internal` after migration to C++17. { @@ -13,10 +15,11 @@ namespace Qis { namespace Internal { - extern char const excStrDrawRandomInt[]; + QIR_SHARED_API extern char const excStrDrawRandomVal[]; - void RandomizeSeed(bool randomize); - int64_t GetLastGeneratedRandomNumber(); + QIR_SHARED_API void RandomizeSeed(bool randomize); + QIR_SHARED_API int64_t GetLastGeneratedRandomI64(); + QIR_SHARED_API double GetLastGeneratedRandomDouble(); } // namespace Internal } // namespace Qis } // namespace Quantum diff --git a/src/Qir/Common/cmake/qir_cmake_include.cmake b/src/Qir/Common/cmake/qir_cmake_include.cmake new file mode 100644 index 00000000000..25e66fbd104 --- /dev/null +++ b/src/Qir/Common/cmake/qir_cmake_include.cmake @@ -0,0 +1,41 @@ +#=============================================================================== +# compiling from IR +macro(target_source_from_qir target_name source_file) + set(CLANG_ARGS "-c") + if (CMAKE_BUILD_TYPE STREQUAL "Debug") + set(CLANG_ARGS + "${CLANG_ARGS}" + "-O0" + "-DDEBUG" + ) + endif() + + get_filename_component(file_name ${source_file} NAME_WLE) + + set(INFILE + "${CMAKE_CURRENT_SOURCE_DIR}/${source_file}" + ) + set(OBJFILE + "${CMAKE_CURRENT_BINARY_DIR}/${file_name}.obj" + ) + + set(OBJFILE_COMPILE "${file_name}-compile") + add_custom_command(OUTPUT ${OBJFILE_COMPILE} + COMMAND ${CMAKE_CXX_COMPILER} + ARGS ${CLANG_ARGS} ${INFILE} "-o" ${OBJFILE} + DEPENDS ${INFILE} + BYPRODUCTS ${OBJFILE} + COMMENT "Compiling ${source_file}" + VERBATIM + ) + add_custom_target(${target_name}_${file_name}_compile DEPENDS ${OBJFILE_COMPILE}) + + set_source_files_properties( + ${OBJFILE} + PROPERTIES + EXTERNAL_OBJECT true + ) + target_sources(${target_name} PUBLIC + ${OBJFILE} + ) +endmacro() diff --git a/src/QirRuntime/cmake/unit_test_include.cmake b/src/Qir/Common/cmake/unit_test_include.cmake similarity index 52% rename from src/QirRuntime/cmake/unit_test_include.cmake rename to src/Qir/Common/cmake/unit_test_include.cmake index b4ac9de981e..4ecaf1e6237 100644 --- a/src/QirRuntime/cmake/unit_test_include.cmake +++ b/src/Qir/Common/cmake/unit_test_include.cmake @@ -1,5 +1,3 @@ -set(test_includes "${PROJECT_SOURCE_DIR}/externals/catch2" "${PROJECT_SOURCE_DIR}/test") - include(CTest) macro(add_unit_test target) add_test( @@ -11,13 +9,14 @@ macro(add_unit_test target) if(DEFINED ENV{NATIVE_SIMULATOR}) set(TEST_DEPS1 $ENV{NATIVE_SIMULATOR}) else() - set(TEST_DEPS1 "${PROJECT_SOURCE_DIR}/../Simulation/native/build/${CMAKE_BUILD_TYPE}") + set(TEST_DEPS1 "${PROJECT_SOURCE_DIR}/../../Simulation/native/build/${CMAKE_BUILD_TYPE}") endif() set(TEST_DEPS2 "${CMAKE_BINARY_DIR}/bin") + set(TEST_DEPS3 "${PROJECT_SOURCE_DIR}/../Runtime/build/${CMAKE_BUILD_TYPE}/bin") set_property(TEST ${target} PROPERTY ENVIRONMENT - "LD_LIBRARY_PATH=${TEST_DEPS1}:${TEST_DEPS2}:${LD_LIBRARY_PATH}" - "PATH=${TEST_DEPS1}\;${TEST_DEPS2}\;${PATH}" - "DYLD_LIBRARY_PATH=${TEST_DEPS1}:${TEST_DEPS2}:${DYLD_LIBRARY_PATH}" + "LD_LIBRARY_PATH=${TEST_DEPS1}:${TEST_DEPS2}:${TEST_DEPS3}:${LD_LIBRARY_PATH}" + "PATH=${TEST_DEPS1}\;${TEST_DEPS2}\;${TEST_DEPS3}\;${PATH}" + "DYLD_LIBRARY_PATH=${TEST_DEPS1}:${TEST_DEPS2}:${TEST_DEPS3}:${DYLD_LIBRARY_PATH}" ) endmacro(add_unit_test) diff --git a/src/QirRuntime/externals/CLI11/CLI11.hpp b/src/Qir/Common/externals/CLI11/CLI11.hpp similarity index 100% rename from src/QirRuntime/externals/CLI11/CLI11.hpp rename to src/Qir/Common/externals/CLI11/CLI11.hpp diff --git a/src/QirRuntime/externals/catch2/catch.hpp b/src/Qir/Common/externals/catch2/catch.hpp similarity index 100% rename from src/QirRuntime/externals/catch2/catch.hpp rename to src/Qir/Common/externals/catch2/catch.hpp diff --git a/src/QirRuntime/externals/cgmanifest.json b/src/Qir/Common/externals/cgmanifest.json similarity index 96% rename from src/QirRuntime/externals/cgmanifest.json rename to src/Qir/Common/externals/cgmanifest.json index 1bd19eceaee..612833415ba 100644 --- a/src/QirRuntime/externals/cgmanifest.json +++ b/src/Qir/Common/externals/cgmanifest.json @@ -1,30 +1,30 @@ -{ - "Registrations":[ - { - "Component": { - "Type": "other", - "Other": { - "Name": "llvm-ar.exe", - "Version": "10.0.0", - "DownloadUrl": "https://github.com/llvm/llvm-project/releases/download/llvmorg-10.0.0/LLVM-10.0.0-win64.exe" - } - } - }, - { - "Component": { - "Type": "git", - "Git": { - "RepositoryUrl": "https://github.com/catchorg/Catch2", - "CommitHash": "87074da73ecb1c2e7c35fd14f50ca21c4c002adc" } - } - }, - { - "Component": { - "Type": "git", - "Git": { - "RepositoryUrl": "https://github.com/CLIUtils/CLI11", - "CommitHash": "5cb3efabce007c3a0230e4cc2e27da491c646b6c" } - } - } - ] +{ + "Registrations":[ + { + "Component": { + "Type": "other", + "Other": { + "Name": "llvm-ar.exe", + "Version": "10.0.0", + "DownloadUrl": "https://github.com/llvm/llvm-project/releases/download/llvmorg-10.0.0/LLVM-10.0.0-win64.exe" + } + } + }, + { + "Component": { + "Type": "git", + "Git": { + "RepositoryUrl": "https://github.com/catchorg/Catch2", + "CommitHash": "87074da73ecb1c2e7c35fd14f50ca21c4c002adc" } + } + }, + { + "Component": { + "Type": "git", + "Git": { + "RepositoryUrl": "https://github.com/CLIUtils/CLI11", + "CommitHash": "5cb3efabce007c3a0230e4cc2e27da491c646b6c" } + } + } + ] } \ No newline at end of file diff --git a/src/QirRuntime/externals/readme.md b/src/Qir/Common/externals/readme.md similarity index 97% rename from src/QirRuntime/externals/readme.md rename to src/Qir/Common/externals/readme.md index 3bef64779af..be24f8dcff5 100644 --- a/src/QirRuntime/externals/readme.md +++ b/src/Qir/Common/externals/readme.md @@ -1,9 +1,9 @@ -# External components - -## Catch2 - -We are using v2.12.1 single-header distribution of catch2 native framework from https://github.com/catchorg/Catch2 (2e61d38c7c3078e600c331257b5bebfb81aaa685). - -## CLI11 - -We are using v1.9.1 single-header distribution of CLI11 command line parser for C++ from (https://github.com/CLIUtils/CLI11) (5cb3efabce007c3a0230e4cc2e27da491c646b6c). +# External components + +## Catch2 + +We are using v2.12.1 single-header distribution of catch2 native framework from https://github.com/catchorg/Catch2 (2e61d38c7c3078e600c331257b5bebfb81aaa685). + +## CLI11 + +We are using v1.9.1 single-header distribution of CLI11 command line parser for C++ from (https://github.com/CLIUtils/CLI11) (5cb3efabce007c3a0230e4cc2e27da491c646b6c). diff --git a/src/Qir/Runtime/CMakeLists.txt b/src/Qir/Runtime/CMakeLists.txt new file mode 100644 index 00000000000..da7f2eaceff --- /dev/null +++ b/src/Qir/Runtime/CMakeLists.txt @@ -0,0 +1,35 @@ +cmake_minimum_required(VERSION 3.10) + +message(INFO "*** build config: ${CMAKE_BUILD_TYPE}") + +# set the project name and version +project(qirruntime) + +# specify the C++ standard, compiler and other tools +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED True) + +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG") + +if(WIN32) + if(CMAKE_BUILD_TYPE STREQUAL "Debug") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_DLL -D_MT -Xclang --dependent-lib=msvcrtd") + else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_DLL -D_MT -Xclang --dependent-lib=msvcrt") + endif() +endif() + +# feel free to customize these flags for your local builds (don't check in) +set(CMAKE_VERBOSE_MAKEFILE ON) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-inline") + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/../Common/cmake") + +set(public_includes "${PROJECT_SOURCE_DIR}/public") +set(common_includes "${PROJECT_SOURCE_DIR}/../Common/Include") + +include(qir_cmake_include) + +add_subdirectory(lib) +add_subdirectory(unittests) diff --git a/src/QirRuntime/README.md b/src/Qir/Runtime/README.md similarity index 74% rename from src/QirRuntime/README.md rename to src/Qir/Runtime/README.md index 3a7f2e4b69b..40d9de3eae7 100644 --- a/src/QirRuntime/README.md +++ b/src/Qir/Runtime/README.md @@ -1,34 +1,30 @@ # The Native QIR Runtime -This folder contains QIR runtime project, which includes implementation of the +This folder contains the Quantum Intermediate Representation (QIR) Runtime project. The QIR is a subset of the [LLVM](https://llvm.org/) Intermediate Representation. +The QIR runtime includes an implementation of the [QIR specification](https://github.com/microsoft/qsharp-language/tree/main/Specifications/QIR) and the bridge to - compile QIR to be run against the native full state simulator. + 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. -- `test` folder contains tests for the runtime +- `unittests` folder contains tests for the runtime - `externals` folder contains external dependencies. We'll strive to keep those minimal. ## Build -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. - -You can use CMake directly. For example, to produce a release build: - -1. navigate into QirRuntime folder -2. mkdir build -3. cd build -4. cmake -G Ninja -DCMAKE_BUILD_TYPE=Release .. -5. cmake --build . - -Or you can run `build-qir-runtime.ps1` script from QirRuntime folder. The script will place the build artifacts into `build/[Debug|Release]` folder. We strongly recommend doing local builds using the build script because it also runs clang-tidy if it is installed. +### Prerequisites -CI builds and tests are enabled for this project. The build for `test/QIR-static/qsharp/qir-gen.csproj` has project dependencies on other parts of the runtime and may trigger a build for those components, while some of the tests depend on `Microsoft.Quantum.Simulator.Runtime` dynamic library built from. +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`)](https://github.com/PowerShell/PowerShell), 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 (Windows script relies on [Chocolatey](https://chocolatey.org/) for installation). +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`](prerequisites.ps1), or manually install pre-reqs with the steps listed below. +Note that on Windows, this script relies on the [Chocolatey package manager](https://chocolatey.org/), +while on macOS, `prerequisites.ps1` relies on the [`brew` package manager](https://brew.sh). -### Windows pre-reqs +#### Windows pre-reqs 1. Install Clang 11, Ninja and CMake from the public distros. 1. Add all three to your/system `%PATH%`. @@ -39,7 +35,7 @@ To install prerequisite tools for building the QIR runtime, you can set the `ENA *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 +#### Linux via WSL pre-reqs 1. On the host Windows machine [enable WSL](https://docs.microsoft.com/en-us/windows/wsl/install-win10) and install Ubuntu 20.04 LTS. @@ -55,35 +51,39 @@ Running cmake from the editors will likely default to MSVC or clang-cl and fail. See [https://code.visualstudio.com/docs/remote/wsl] on how to use VS Code with WSL. -## Test +#### 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`](../../README.md#building-from-source) +(up to and including the step `Simulation.sln`). -Some of the tests depend on Microsoft.Quantum.Simulator.Runtime library. To run them make sure to build Native simulator - from this repository or provide your own version of the library in a folder the OS would search during dynamic library - lookup. -Some of the tests use generated QIR (*.ll) files as build input. Currently the files are checked-in as part of the project - but in the future they will be replaced by automatic generation during build. To regenerate the files, run generateqir.py - or build/test scripts without specifying `noqirgen`. To use the checked-in files without regenerating them, run build/test - scripts with `noqirgen` argument. +### Build Commands -### Running tests with test.py +To build QirRuntime you can run [`build-qir-runtime.ps1`](build-qir-runtime.ps1) script from QirRuntime folder: +```batch +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`](../../build/set-env.ps1). -To execute all tests locally run `test.py` from the project's root folder: +## Tests -- (Windows) `python test.py [nobuild] [debug/release]` -- (Linux) `python3 test.py [nobuild] [debug/release]` +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. -The script will trigger an incremental build unless `nobuild` options is specified. Tests from the "[skip]" category - won't be run. +### Running All Tests -### Running tests with CTest +```powershell +# Navigate to QirRuntime folder. -All native tests, including QIR, use catch2 and are fully integrated with CTest. Navigate into - `build/[Windows|Linux]/[Debug|Release]` folder and run `ctest`. No configuration options required. The results will be - logged into the corresponding `build/[Windows|Linux]/[Debug|Release]//_results.xml` file. - Tests from the "[skip]" category won't be run. +pwsh test-qir-runtime.ps1 +``` -### Running test binaries individually +### Running Test Binaries Individually ` -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 ` ~[skip]`. diff --git a/src/Qir/Runtime/build-qir-runtime.ps1 b/src/Qir/Runtime/build-qir-runtime.ps1 new file mode 100644 index 00000000000..d9e8f6e06df --- /dev/null +++ b/src/Qir/Runtime/build-qir-runtime.ps1 @@ -0,0 +1,8 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +. (Join-Path $PSScriptRoot .. qir-utils.ps1) + +if (-not (Build-CMakeProject $PSScriptRoot "QIR Runtime")) { + throw "At least one project failed to compile. Check the logs." +} diff --git a/src/QirRuntime/lib/CMakeLists.txt b/src/Qir/Runtime/lib/CMakeLists.txt similarity index 100% rename from src/QirRuntime/lib/CMakeLists.txt rename to src/Qir/Runtime/lib/CMakeLists.txt diff --git a/src/QirRuntime/lib/QIR/.clang-tidy b/src/Qir/Runtime/lib/QIR/.clang-tidy similarity index 100% rename from src/QirRuntime/lib/QIR/.clang-tidy rename to src/Qir/Runtime/lib/QIR/.clang-tidy diff --git a/src/QirRuntime/lib/QIR/CMakeLists.txt b/src/Qir/Runtime/lib/QIR/CMakeLists.txt similarity index 74% rename from src/QirRuntime/lib/QIR/CMakeLists.txt rename to src/Qir/Runtime/lib/QIR/CMakeLists.txt index 8f1d7226ee1..4bae717ec85 100644 --- a/src/QirRuntime/lib/QIR/CMakeLists.txt +++ b/src/Qir/Runtime/lib/QIR/CMakeLists.txt @@ -5,12 +5,6 @@ # qir-rt #+++++++++++++++++++++++++++++++++++++ -#=============================================================================== -# create a utility lib from bridge-rt.ll -# -set(bridge_rt_target "bridge_rt_target") -compile_from_qir(bridge-rt ${bridge_rt_target}) - #=============================================================================== # create qir-rt-support lib from the C++ sources # @@ -22,16 +16,12 @@ set(rt_sup_source_files delegated.cpp strings.cpp utils.cpp + rtOut.cpp ) -add_library(qir-rt-support ${rt_sup_source_files}) -target_include_directories(qir-rt-support PUBLIC ${public_includes}) -add_dependencies(qir-rt-support ${bridge_rt_target}) -target_compile_definitions(qir-rt-support PRIVATE EXPORT_QIR_API) - # Produce object lib we'll use to create a shared lib (so/dll) later on add_library(qir-rt-support-obj OBJECT ${rt_sup_source_files}) -target_source_from_qir_obj(qir-rt-support-obj bridge-rt) +target_source_from_qir(qir-rt-support-obj bridge-rt.ll) target_include_directories(qir-rt-support-obj PUBLIC ${public_includes}) set_property(TARGET qir-rt-support-obj PROPERTY POSITION_INDEPENDENT_CODE ON) target_compile_definitions(qir-rt-support-obj PRIVATE EXPORT_QIR_API) diff --git a/src/QirRuntime/lib/QIR/allocationsTracker.cpp b/src/Qir/Runtime/lib/QIR/allocationsTracker.cpp similarity index 100% rename from src/QirRuntime/lib/QIR/allocationsTracker.cpp rename to src/Qir/Runtime/lib/QIR/allocationsTracker.cpp diff --git a/src/QirRuntime/lib/QIR/allocationsTracker.hpp b/src/Qir/Runtime/lib/QIR/allocationsTracker.hpp similarity index 100% rename from src/QirRuntime/lib/QIR/allocationsTracker.hpp rename to src/Qir/Runtime/lib/QIR/allocationsTracker.hpp diff --git a/src/QirRuntime/lib/QIR/arrays.cpp b/src/Qir/Runtime/lib/QIR/arrays.cpp similarity index 96% rename from src/QirRuntime/lib/QIR/arrays.cpp rename to src/Qir/Runtime/lib/QIR/arrays.cpp index 00d8d9e19c6..54c68d08b82 100644 --- a/src/QirRuntime/lib/QIR/arrays.cpp +++ b/src/Qir/Runtime/lib/QIR/arrays.cpp @@ -231,6 +231,8 @@ extern "C" qa->ownsQubits = false; } + + quantum__rt__array_update_reference_count(qa, -1); } QirArray* quantum__rt__array_create_1d(int32_t itemSizeInBytes, int64_t count_items) diff --git a/src/QirRuntime/lib/QIR/bridge-rt.ll b/src/Qir/Runtime/lib/QIR/bridge-rt.ll similarity index 86% rename from src/QirRuntime/lib/QIR/bridge-rt.ll rename to src/Qir/Runtime/lib/QIR/bridge-rt.ll index f27357e918c..c792e72cb82 100644 --- a/src/QirRuntime/lib/QIR/bridge-rt.ll +++ b/src/Qir/Runtime/lib/QIR/bridge-rt.ll @@ -37,8 +37,9 @@ ;------------------------------------------------------------------------------ ; classical ; -declare i8* @quantum__rt__heap_alloc(i32) +declare i8* @quantum__rt__heap_alloc(i64) declare void @quantum__rt__heap_free(i8*) +declare i8* @quantum__rt__memory_allocate(i64) declare void @quantum__rt__fail(%"struct.QirString"*) ;------------------------------------------------------------------------------ @@ -48,6 +49,8 @@ declare %class.QUBIT* @quantum__rt__qubit_allocate() declare void @quantum__rt__qubit_release(%class.QUBIT*) declare i1 @quantum__rt__result_equal(%class.RESULT*, %class.RESULT*) declare void @quantum__rt__result_update_reference_count(%class.RESULT* %r, i32 %c) +declare %class.RESULT* @quantum__rt__result_get_zero() +declare %class.RESULT* @quantum__rt__result_get_one() ;------------------------------------------------------------------------------ ; arrays @@ -85,7 +88,7 @@ declare %"struct.QirCallable"* @quantum__rt__callable_copy(%"struct.QirCallable" declare %"struct.QirCallable"* @quantum__rt__callable_make_adjoint(%"struct.QirCallable"*) declare %"struct.QirCallable"* @quantum__rt__callable_make_controlled(%"struct.QirCallable"*) declare void @quantum__rt__callable_update_alias_count(%"struct.QirCallable"*, i32) -declare void @quantum__rt__callable_memory_management(i32, %"struct.QirCallable"*, i64) +declare void @quantum__rt__callable_memory_management(i32, %"struct.QirCallable"*, i32) ;------------------------------------------------------------------------------ ; strings @@ -101,8 +104,14 @@ declare %"struct.QirString"* @quantum__rt__result_to_string(%class.RESULT*) declare %"struct.QirString"* @quantum__rt__pauli_to_string(%PauliId) declare %"struct.QirString"* @quantum__rt__qubit_to_string(%class.QUBIT*) declare %"struct.QirString"* @quantum__rt__range_to_string(%"struct.QirRange"* dereferenceable(24) %range) +declare i8* @quantum__rt__string_get_data(%"struct.QirString"* %str) +declare i32 @quantum__rt__string_get_length(%"struct.QirString"* %str) +;------------------------------------------------------------------------------ +; message +; +declare void @quantum__rt__message(%"struct.QirString"* %str) ;======================================================================================================================= ; __quantum__rt__* bridge implementation @@ -111,8 +120,8 @@ declare %"struct.QirString"* @quantum__rt__range_to_string(%"struct.QirRange"* d ;------------------------------------------------------------------------------ ; classical bridge ; -define dllexport i8* @__quantum__rt__heap_alloc(i32 %size) { - %mem = call i8* @quantum__rt__heap_alloc(i32 %size) +define dllexport i8* @__quantum__rt__heap_alloc(i64 %size) { + %mem = call i8* @quantum__rt__heap_alloc(i64 %size) ret i8* %mem } @@ -121,12 +130,24 @@ define dllexport void @__quantum__rt__heap_free(i8* %mem) { ret void } +; Returns a pointer to the malloc-allocated block. +define dllexport i8* @__quantum__rt__memory_allocate(i64 %size) { + %result = call i8* @quantum__rt__memory_allocate(i64 %size) + ret i8* %result +} + define dllexport void @__quantum__rt__fail(%String* %.str) { %str = bitcast %String* %.str to %"struct.QirString"* call void @quantum__rt__fail(%"struct.QirString"* %str) ret void } +define dllexport void @__quantum__rt__message(%String* %.str) { + %str = bitcast %String* %.str to %"struct.QirString"* + call void @quantum__rt__message(%"struct.QirString"* %str) + ret void +} + ;------------------------------------------------------------------------------ ; qubits bridge @@ -172,13 +193,24 @@ define dllexport i1 @__quantum__rt__result_equal(%Result* %.r1, %Result* %.r2) { ret i1 %c } -define dllexport void @__quantum__rt__result_update_reference_count(%Result* %.r, i64 %.c) { +define dllexport void @__quantum__rt__result_update_reference_count(%Result* %.r, i32 %c) { %r = bitcast %Result* %.r to %class.RESULT* - %c = trunc i64 %.c to i32 call void @quantum__rt__result_update_reference_count(%class.RESULT* %r, i32 %c) ret void } +define dllexport %Result* @__quantum__rt__result_get_zero() { + %result = call %class.RESULT* @quantum__rt__result_get_zero() + %.result = bitcast %class.RESULT* %result to %Result* + ret %Result* %.result +} + +define dllexport %Result* @__quantum__rt__result_get_one() { + %result = call %class.RESULT* @quantum__rt__result_get_one() + %.result = bitcast %class.RESULT* %result to %Result* + ret %Result* %.result +} + ; ----------------------------------------------------------------------------- ; arrays bridge @@ -276,16 +308,14 @@ define dllexport %Array* @__quantum__rt__array_slice_1d(%Array* %.ar, %Range %.r ret %Array* %.slice } -define dllexport void @__quantum__rt__array_update_reference_count(%Array* %.ar, i64 %.c) { +define dllexport void @__quantum__rt__array_update_reference_count(%Array* %.ar, i32 %c) { %ar = bitcast %Array* %.ar to %"struct.QirArray"* - %c = trunc i64 %.c to i32 call void @quantum__rt__array_update_reference_count(%"struct.QirArray"* %ar, i32 %c) ret void } -define dllexport void @__quantum__rt__array_update_alias_count(%Array* %.ar, i64 %.c) { +define dllexport void @__quantum__rt__array_update_alias_count(%Array* %.ar, i32 %c) { %ar = bitcast %Array* %.ar to %"struct.QirArray"* - %c = trunc i64 %.c to i32 call void @quantum__rt__array_update_alias_count(%"struct.QirArray"* %ar, i32 %c) ret void } @@ -299,16 +329,14 @@ define dllexport %Tuple* @__quantum__rt__tuple_create(i64 %size) { ret %Tuple* %.th } -define dllexport void @__quantum__rt__tuple_update_reference_count(%Tuple* %.th, i64 %.c) { +define dllexport void @__quantum__rt__tuple_update_reference_count(%Tuple* %.th, i32 %c) { %th = bitcast %Tuple* %.th to i8* - %c = trunc i64 %.c to i32 call void @quantum__rt__tuple_update_reference_count(i8* %th, i32 %c) ret void } -define dllexport void @__quantum__rt__tuple_update_alias_count(%Tuple* %.th, i64 %.c) { +define dllexport void @__quantum__rt__tuple_update_alias_count(%Tuple* %.th, i32 %c) { %th = bitcast %Tuple* %.th to i8* - %c = trunc i64 %.c to i32 call void @quantum__rt__tuple_update_alias_count(i8* %th, i32 %c) ret void } @@ -316,16 +344,14 @@ define dllexport void @__quantum__rt__tuple_update_alias_count(%Tuple* %.th, i64 ;------------------------------------------------------------------------------ ; callables bridge ; -define dllexport void @__quantum__rt__callable_update_reference_count(%Callable* %.clb, i64 %.c) { +define dllexport void @__quantum__rt__callable_update_reference_count(%Callable* %.clb, i32 %c) { %clb = bitcast %Callable* %.clb to %"struct.QirCallable"* - %c = trunc i64 %.c to i32 call void @quantum__rt__callable_update_reference_count(%"struct.QirCallable"* %clb, i32 %c) ret void } -define dllexport void @__quantum__rt__callable_update_alias_count(%Callable* %.clb, i64 %.c) { +define dllexport void @__quantum__rt__callable_update_alias_count(%Callable* %.clb, i32 %c) { %clb = bitcast %Callable* %.clb to %"struct.QirCallable"* - %c = trunc i64 %.c to i32 call void @quantum__rt__callable_update_alias_count(%"struct.QirCallable"* %clb, i32 %c) ret void } @@ -370,26 +396,32 @@ define dllexport %Callable* @__quantum__rt__callable_make_controlled(%Callable* ret %Callable* %.clb_cnt } -define dllexport void @__quantum__rt__callable_memory_management(i32 %index, %Callable* %.clb, i64 %parameter) { +define dllexport void @__quantum__rt__capture_update_reference_count(%Callable* %.clb, i32 %count) { %clb = bitcast %Callable* %.clb to %"struct.QirCallable"* - call void @quantum__rt__callable_memory_management(i32 %index, %"struct.QirCallable"* %clb, i64 %parameter) + call void @quantum__rt__callable_memory_management(i32 0, %"struct.QirCallable"* %clb, i32 %count) ret void } + +define dllexport void @__quantum__rt__capture_update_alias_count(%Callable* %.clb, i32 %count) { + %clb = bitcast %Callable* %.clb to %"struct.QirCallable"* + call void @quantum__rt__callable_memory_management(i32 1, %"struct.QirCallable"* %clb, i32 %count) + ret void +} + ;------------------------------------------------------------------------------ ; strings bridge ; ; NYI: ;define dllexport %String* @__quantum__rt__bigint_to_string(%BigInt*) -define dllexport %String* @__quantum__rt__string_create(i32 %length_ignored, i8* %null_terminated_buffer) { +define dllexport %String* @__quantum__rt__string_create(i8* %null_terminated_buffer) { %str = call %"struct.QirString"* @quantum__rt__string_create(i8* %null_terminated_buffer) %.str = bitcast %"struct.QirString"* %str to %String* ret %String* %.str } -define dllexport void @__quantum__rt__string_update_reference_count(%String* %.str, i64 %.c) { +define dllexport void @__quantum__rt__string_update_reference_count(%String* %.str, i32 %c) { %str = bitcast %String* %.str to %"struct.QirString"* - %c = trunc i64 %.c to i32 call void @quantum__rt__string_update_reference_count(%"struct.QirString"* %str, i32 %c) ret void } @@ -458,13 +490,27 @@ define dllexport %String* @__quantum__rt__range_to_string(%Range %.range) { ret %String* %.str } +define dllexport i8* @__quantum__rt__string_get_data(%String* %.str) { + %str = bitcast %String* %.str to %"struct.QirString"* + %result = call i8* @quantum__rt__string_get_data(%"struct.QirString"* %str) + ret i8* %result +} + +define dllexport i32 @__quantum__rt__string_get_length(%String* %.str) { + %str = bitcast %String* %.str to %"struct.QirString"* + %result = call i32 @quantum__rt__string_get_length(%"struct.QirString"* %str) + ret i32 %result +} + + + ;------------------------------------------------------------------------------ ; bigints bridge ; ; NYI: ;define dllexport %BigInt* @__quantum__rt__bigint_create_i64(i64) ;define dllexport %BigInt* @__quantum__rt__bigint_create_array(i32, [0 x i8]) -;define dllexport void @__quantum__rt__bigint_update_reference_count(%BigInt*, i64) +;define dllexport void @__quantum__rt__bigint_update_reference_count(%BigInt*, i32) ;define dllexport %BigInt* @__quantum__rt__bigint_negate(%BigInt*) ;define dllexport %BigInt* @__quantum__rt__bigint_add(%BigInt*, %BigInt*) ;define dllexport %BigInt* @__quantum__rt__bigint_subtract(%BigInt*, %BigInt*) diff --git a/src/QirRuntime/lib/QIR/callables.cpp b/src/Qir/Runtime/lib/QIR/callables.cpp similarity index 95% rename from src/QirRuntime/lib/QIR/callables.cpp rename to src/Qir/Runtime/lib/QIR/callables.cpp index 454eb4f3dbf..f63bc44dc03 100644 --- a/src/QirRuntime/lib/QIR/callables.cpp +++ b/src/Qir/Runtime/lib/QIR/callables.cpp @@ -153,7 +153,7 @@ extern "C" callable->ApplyFunctor(QirCallable::Controlled); } - void quantum__rt__callable_memory_management(int32_t index, QirCallable* callable, int64_t parameter) + void quantum__rt__callable_memory_management(int32_t index, QirCallable* callable, int32_t parameter) { callable->InvokeCaptureCallback(index, parameter); } @@ -181,13 +181,13 @@ int QirTupleHeader::Release() } assert(this->refCount > 0); // doesn't guarantee we catch double releases but better than nothing - --this->refCount; + int retVal = --this->refCount; if (this->refCount == 0) { char* buffer = reinterpret_cast(this); delete[] buffer; } - return this->refCount; + return retVal; } QirTupleHeader* QirTupleHeader::Create(int size) @@ -443,7 +443,7 @@ void QirCallable::ApplyFunctor(int functor) } } -void QirCallable::InvokeCaptureCallback(int index, int64_t parameter) +void QirCallable::InvokeCaptureCallback(int32_t index, int32_t parameter) { assert(index >= 0 && index < QirCallable::CaptureCallbacksTableSize && "Capture callback index out of range"); diff --git a/src/QirRuntime/lib/QIR/context.cpp b/src/Qir/Runtime/lib/QIR/context.cpp similarity index 100% rename from src/QirRuntime/lib/QIR/context.cpp rename to src/Qir/Runtime/lib/QIR/context.cpp diff --git a/src/QirRuntime/lib/QIR/delegated.cpp b/src/Qir/Runtime/lib/QIR/delegated.cpp similarity index 95% rename from src/QirRuntime/lib/QIR/delegated.cpp rename to src/Qir/Runtime/lib/QIR/delegated.cpp index 7100fcef9aa..8d466b086f4 100644 --- a/src/QirRuntime/lib/QIR/delegated.cpp +++ b/src/Qir/Runtime/lib/QIR/delegated.cpp @@ -27,12 +27,12 @@ std::unordered_map& AllocatedResults() extern "C" { - Result quantum__rt__result_zero() + Result quantum__rt__result_get_zero() { return Microsoft::Quantum::g_context->driver->UseZero(); } - Result quantum__rt__result_one() + Result quantum__rt__result_get_one() { return Microsoft::Quantum::g_context->driver->UseOne(); } diff --git a/src/QirRuntime/lib/QSharpFoundation/intrinsicsOut.cpp b/src/Qir/Runtime/lib/QIR/rtOut.cpp similarity index 86% rename from src/QirRuntime/lib/QSharpFoundation/intrinsicsOut.cpp rename to src/Qir/Runtime/lib/QIR/rtOut.cpp index 99eb2292dac..5f921c706fc 100644 --- a/src/QirRuntime/lib/QSharpFoundation/intrinsicsOut.cpp +++ b/src/Qir/Runtime/lib/QIR/rtOut.cpp @@ -4,8 +4,7 @@ #include #include "QirTypes.hpp" -#include "SimFactory.hpp" -#include "qsharp__foundation__qis.hpp" +#include "QirRuntime.hpp" // Forward declarations: static std::ostream& GetOutputStream(); @@ -13,7 +12,7 @@ static std::ostream& GetOutputStream(); // Public API: extern "C" { - void quantum__qis__message__body(QirString* qstr) // NOLINT + void quantum__rt__message(QirString* qstr) // NOLINT { GetOutputStream() << qstr->str << std::endl; } diff --git a/src/QirRuntime/lib/QIR/strings.cpp b/src/Qir/Runtime/lib/QIR/strings.cpp similarity index 92% rename from src/QirRuntime/lib/QIR/strings.cpp rename to src/Qir/Runtime/lib/QIR/strings.cpp index 21f3b571d14..5027a88c1fd 100644 --- a/src/QirRuntime/lib/QIR/strings.cpp +++ b/src/Qir/Runtime/lib/QIR/strings.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "QirTypes.hpp" #include "QirRuntime.hpp" @@ -155,6 +156,16 @@ extern "C" return quantum__rt__string_create(oss.str().c_str()); } + const char* quantum__rt__string_get_data(QirString* str) // NOLINT + { + return str->str.c_str(); + } + + uint32_t quantum__rt__string_get_length(QirString* str) // NOLINT + { + return str->str.size(); + } + // Implemented in delegated.cpp: // QirString* quantum__rt__qubit_to_string(QUBIT* qubit); // NOLINT diff --git a/src/QirRuntime/lib/QIR/utils.cpp b/src/Qir/Runtime/lib/QIR/utils.cpp similarity index 72% rename from src/QirRuntime/lib/QIR/utils.cpp rename to src/Qir/Runtime/lib/QIR/utils.cpp index 6f024cdfafe..16ab94fa645 100644 --- a/src/QirRuntime/lib/QIR/utils.cpp +++ b/src/Qir/Runtime/lib/QIR/utils.cpp @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include "QirRuntime.hpp" @@ -20,9 +22,13 @@ std::unordered_set& UseMemoryTracker() extern "C" { // Allocate a block of memory on the heap. - char* quantum__rt__heap_alloc(int size) // NOLINT + char* quantum__rt__heap_alloc(uint64_t size) // NOLINT { - char* buffer = new char[size]; + char* buffer = new (std::nothrow) char[size]; + if(buffer == nullptr) + { + quantum__rt__fail(quantum__rt__string_create("Allocation Failed")); + } #ifndef NDEBUG UseMemoryTracker().insert(buffer); #endif @@ -40,6 +46,11 @@ extern "C" delete[] buffer; } + char* quantum__rt__memory_allocate(uint64_t size) + { + return (char *)malloc((size_t)size); + } + // Fail the computation with the given error message. void quantum__rt__fail(QirString* msg) // NOLINT { @@ -48,10 +59,4 @@ extern "C" throw std::runtime_error(str); } - // Include the given message in the computation's execution log or equivalent. - // TODO: should we allow the user to register their own output? - void quantum__rt__message(QirString* msg) // NOLINT - { - std::cout << msg->str; - } } \ No newline at end of file diff --git a/src/QirRuntime/lib/QSharpCore/.clang-tidy b/src/Qir/Runtime/lib/QSharpCore/.clang-tidy similarity index 100% rename from src/QirRuntime/lib/QSharpCore/.clang-tidy rename to src/Qir/Runtime/lib/QSharpCore/.clang-tidy diff --git a/src/QirRuntime/lib/QSharpCore/CMakeLists.txt b/src/Qir/Runtime/lib/QSharpCore/CMakeLists.txt similarity index 71% rename from src/QirRuntime/lib/QSharpCore/CMakeLists.txt rename to src/Qir/Runtime/lib/QSharpCore/CMakeLists.txt index e0f334f5789..721ea8b0a46 100644 --- a/src/QirRuntime/lib/QSharpCore/CMakeLists.txt +++ b/src/Qir/Runtime/lib/QSharpCore/CMakeLists.txt @@ -2,12 +2,6 @@ # qsharp-core-qis #+++++++++++++++++++++++++++++++++++++ -#=============================================================================== -# create a utility lib from qsharp-core-qis.ll -# -set(qsharp_core_qis_target "qsharp_core_qis_target") -compile_from_qir(qsharp-core-qis ${qsharp_core_qis_target}) - #=============================================================================== # create qsharp-core-qis-support lib from the C++ sources # @@ -15,14 +9,9 @@ set(qsharp_core_sup_source_files intrinsics.cpp ) -add_library(qsharp-core-qis-support ${qsharp_core_sup_source_files}) -target_include_directories(qsharp-core-qis-support PUBLIC ${public_includes}) -add_dependencies(qsharp-core-qis-support ${qsharp_core_qis_target}) -target_compile_definitions(qsharp-core-qis-support PRIVATE EXPORT_QIR_API) - # Produce object lib we'll use to create a shared lib (so/dll) later on add_library(qsharp-core-qis-support-obj OBJECT ${qsharp_core_sup_source_files}) -target_source_from_qir_obj(qsharp-core-qis-support-obj qsharp-core-qis) +target_source_from_qir(qsharp-core-qis-support-obj qsharp-core-qis.ll) target_include_directories(qsharp-core-qis-support-obj PUBLIC ${public_includes}) set_property(TARGET qsharp-core-qis-support-obj PROPERTY POSITION_INDEPENDENT_CODE ON) target_compile_definitions(qsharp-core-qis-support-obj PUBLIC EXPORT_QIR_API) @@ -39,6 +28,7 @@ target_link_libraries(Microsoft.Quantum.Qir.QSharp.Core "-L${CMAKE_BINARY_DIR}/lib/QIR" -lMicrosoft.Quantum.Qir.Runtime ) +add_dependencies(Microsoft.Quantum.Qir.QSharp.Core Microsoft.Quantum.Qir.Runtime) target_include_directories(Microsoft.Quantum.Qir.QSharp.Core PUBLIC ${public_includes}) target_compile_definitions(Microsoft.Quantum.Qir.QSharp.Core PRIVATE EXPORT_QIR_API) diff --git a/src/QirRuntime/lib/QSharpCore/intrinsics.cpp b/src/Qir/Runtime/lib/QSharpCore/intrinsics.cpp similarity index 100% rename from src/QirRuntime/lib/QSharpCore/intrinsics.cpp rename to src/Qir/Runtime/lib/QSharpCore/intrinsics.cpp diff --git a/src/QirRuntime/lib/QSharpCore/qsharp-core-qis.ll b/src/Qir/Runtime/lib/QSharpCore/qsharp-core-qis.ll similarity index 100% rename from src/QirRuntime/lib/QSharpCore/qsharp-core-qis.ll rename to src/Qir/Runtime/lib/QSharpCore/qsharp-core-qis.ll diff --git a/src/QirRuntime/lib/QSharpCore/qsharp__core__qis.hpp b/src/Qir/Runtime/lib/QSharpCore/qsharp__core__qis.hpp similarity index 100% rename from src/QirRuntime/lib/QSharpCore/qsharp__core__qis.hpp rename to src/Qir/Runtime/lib/QSharpCore/qsharp__core__qis.hpp diff --git a/src/QirRuntime/lib/QSharpFoundation/CMakeLists.txt b/src/Qir/Runtime/lib/QSharpFoundation/CMakeLists.txt similarity index 67% rename from src/QirRuntime/lib/QSharpFoundation/CMakeLists.txt rename to src/Qir/Runtime/lib/QSharpFoundation/CMakeLists.txt index 6318dc7f062..47ced481af0 100644 --- a/src/QirRuntime/lib/QSharpFoundation/CMakeLists.txt +++ b/src/Qir/Runtime/lib/QSharpFoundation/CMakeLists.txt @@ -2,30 +2,21 @@ # qsharp-foundation-qis #+++++++++++++++++++++++++++++++++++++ -#=============================================================================== -# create a utility lib from qsharp-foundation-qis.ll -# -set(qsharp_foundation_qis_target "qsharp_foundation_qis_target") -compile_from_qir(qsharp-foundation-qis ${qsharp_foundation_qis_target}) - #=============================================================================== # create qsharp-foundation-qis-support lib from the C++ sources # set(qsharp_foundation_sup_source_files intrinsicsMath.cpp - intrinsicsOut.cpp conditionals.cpp ) -add_library(qsharp-foundation-qis-support ${qsharp_foundation_sup_source_files}) -target_include_directories(qsharp-foundation-qis-support PUBLIC ${public_includes}) -add_dependencies(qsharp-foundation-qis-support ${qsharp_foundation_qis_target}) -target_compile_definitions(qsharp-foundation-qis-support PRIVATE EXPORT_QIR_API) - # Produce object lib we'll use to create a shared lib (so/dll) later on add_library(qsharp-foundation-qis-support-obj OBJECT ${qsharp_foundation_sup_source_files}) -target_source_from_qir_obj(qsharp-foundation-qis-support-obj qsharp-foundation-qis) -target_include_directories(qsharp-foundation-qis-support-obj PUBLIC ${public_includes}) +target_source_from_qir(qsharp-foundation-qis-support-obj qsharp-foundation-qis.ll) +target_include_directories(qsharp-foundation-qis-support-obj PUBLIC + ${public_includes} + ${common_includes} +) set_property(TARGET qsharp-foundation-qis-support-obj PROPERTY POSITION_INDEPENDENT_CODE ON) target_compile_definitions(qsharp-foundation-qis-support-obj PUBLIC EXPORT_QIR_API) @@ -40,8 +31,12 @@ target_link_libraries(Microsoft.Quantum.Qir.QSharp.Foundation "-L${CMAKE_BINARY_DIR}/lib/QIR" -lMicrosoft.Quantum.Qir.Runtime ) +add_dependencies(Microsoft.Quantum.Qir.QSharp.Foundation Microsoft.Quantum.Qir.Runtime) -target_include_directories(Microsoft.Quantum.Qir.QSharp.Foundation PUBLIC ${public_includes}) +target_include_directories(Microsoft.Quantum.Qir.QSharp.Foundation PUBLIC + ${public_includes} + ${common_includes} +) target_compile_definitions(Microsoft.Quantum.Qir.QSharp.Foundation PRIVATE EXPORT_QIR_API) set_property(TARGET Microsoft.Quantum.Qir.QSharp.Foundation PROPERTY POSITION_INDEPENDENT_CODE ON) diff --git a/src/QirRuntime/lib/QSharpFoundation/conditionals.cpp b/src/Qir/Runtime/lib/QSharpFoundation/conditionals.cpp similarity index 96% rename from src/QirRuntime/lib/QSharpFoundation/conditionals.cpp rename to src/Qir/Runtime/lib/QSharpFoundation/conditionals.cpp index 048ce01eadb..64e46c846f2 100644 --- a/src/QirRuntime/lib/QSharpFoundation/conditionals.cpp +++ b/src/Qir/Runtime/lib/QSharpFoundation/conditionals.cpp @@ -31,7 +31,7 @@ extern "C" { void quantum__qis__applyifelseintrinsic__body(RESULT* r, QirCallable* clbOnZero, QirCallable* clbOnOne) { - QirCallable* clb = quantum__rt__result_equal(r, quantum__rt__result_zero()) ? clbOnZero : clbOnOne; + QirCallable* clb = quantum__rt__result_equal(r, quantum__rt__result_get_zero()) ? clbOnZero : clbOnOne; clb->Invoke(); } diff --git a/src/QirRuntime/lib/QSharpFoundation/intrinsicsMath.cpp b/src/Qir/Runtime/lib/QSharpFoundation/intrinsicsMath.cpp similarity index 63% rename from src/QirRuntime/lib/QSharpFoundation/intrinsicsMath.cpp rename to src/Qir/Runtime/lib/QSharpFoundation/intrinsicsMath.cpp index cc22595ebe3..4a0a206d58a 100644 --- a/src/QirRuntime/lib/QSharpFoundation/intrinsicsMath.cpp +++ b/src/Qir/Runtime/lib/QSharpFoundation/intrinsicsMath.cpp @@ -12,7 +12,8 @@ namespace // Visible in this translation unit only. { extern thread_local bool randomizeSeed; -extern int64_t lastGeneratedRndNum; +extern int64_t lastGeneratedRndI64; +extern double lastGeneratedRndDouble; } // Implementation: @@ -74,7 +75,7 @@ int64_t quantum__qis__drawrandomint__body(int64_t minimum, int64_t maximum) { if(minimum > maximum) { - quantum__rt__fail(quantum__rt__string_create(Quantum::Qis::Internal::excStrDrawRandomInt)); + quantum__rt__fail(quantum__rt__string_create(Quantum::Qis::Internal::excStrDrawRandomVal)); } // https://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution @@ -83,8 +84,30 @@ int64_t quantum__qis__drawrandomint__body(int64_t minimum, int64_t maximum) ? std::random_device()() : // Default 0); // For test purposes only. - lastGeneratedRndNum = std::uniform_int_distribution(minimum, maximum)(gen); - return lastGeneratedRndNum; + lastGeneratedRndI64 = std::uniform_int_distribution(minimum, maximum)(gen); + return lastGeneratedRndI64; +} + +double quantum__qis__drawrandomdouble__body(double minimum, double maximum) +{ + if(minimum > maximum) + { + quantum__rt__fail(quantum__rt__string_create(Quantum::Qis::Internal::excStrDrawRandomVal)); + } + + // For testing purposes we need separate generators for Int and Double: + // https://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution + // https://en.cppreference.com/w/cpp/numeric/random + thread_local static std::mt19937_64 gen(randomizeSeed + ? std::random_device()() : // Default + 0); // For test purposes only. + + // https://en.cppreference.com/w/cpp/numeric/random/uniform_real_distribution + lastGeneratedRndDouble = std::uniform_real_distribution( + minimum, + std::nextafter(maximum, std::numeric_limits::max())) // "Notes" section. + (gen); + return lastGeneratedRndDouble; } } // extern "C" @@ -92,7 +115,8 @@ int64_t quantum__qis__drawrandomint__body(int64_t minimum, int64_t maximum) namespace // Visible in this translation unit only. { thread_local bool randomizeSeed = true; -int64_t lastGeneratedRndNum = 0; +int64_t lastGeneratedRndI64 = 0; +double lastGeneratedRndDouble = 0.0; } // For test purposes only: @@ -102,17 +126,23 @@ namespace Qis { namespace Internal { - char const excStrDrawRandomInt[] = "Invalid Argument: minimum > maximum for DrawRandomInt()"; + char const excStrDrawRandomVal[] = "Invalid Argument: minimum > maximum"; void RandomizeSeed(bool randomize) { randomizeSeed = randomize; } - int64_t GetLastGeneratedRandomNumber() + int64_t GetLastGeneratedRandomI64() { - return lastGeneratedRndNum; + return lastGeneratedRndI64; } + + double GetLastGeneratedRandomDouble() + { + return lastGeneratedRndDouble; + } + } // namespace Internal } // namespace Qis } // namespace Quantum diff --git a/src/QirRuntime/lib/QSharpFoundation/qsharp-foundation-qis.ll b/src/Qir/Runtime/lib/QSharpFoundation/qsharp-foundation-qis.ll similarity index 93% rename from src/QirRuntime/lib/QSharpFoundation/qsharp-foundation-qis.ll rename to src/Qir/Runtime/lib/QSharpFoundation/qsharp-foundation-qis.ll index 4bc362335c1..3e8a749e187 100644 --- a/src/QirRuntime/lib/QSharpFoundation/qsharp-foundation-qis.ll +++ b/src/Qir/Runtime/lib/QSharpFoundation/qsharp-foundation-qis.ll @@ -31,13 +31,14 @@ %struct.QirString = type opaque %PauliId = type i32 -declare void @quantum__qis__message__body(%struct.QirString* %str) +declare void @quantum__rt__message(%"struct.QirString"* %str) ;=============================================================================== ; +; To do: remove this function after the https://github.com/microsoft/qsharp-runtime/issues/578 is resolved. define dllexport void @__quantum__qis__message__body(%String* %.str) { %str = bitcast %String* %.str to %struct.QirString* - call void @quantum__qis__message__body(%struct.QirString* %str) + call void @quantum__rt__message(%"struct.QirString"* %str) ret void } @@ -63,6 +64,7 @@ declare double @quantum__qis__arccos__body(double %theta) declare double @quantum__qis__arctan__body(double %theta) declare double @quantum__qis__ieeeremainder__body(double %y, double %x) declare i64 @quantum__qis__drawrandomint__body(i64 %min, i64 %max) +declare double @quantum__qis__drawrandomdouble__body(double %min, double %max) ; API for the user code: define dllexport double @__quantum__qis__nan__body() { ; Q#: function NAN() : Double http://www.cplusplus.com/reference/cmath/nan-function/ @@ -190,6 +192,15 @@ define dllexport i64 @__quantum__qis__drawrandomint__body(i64 %min, i64 %max) { ret i64 %result } +; operation DrawRandomDouble (min : Double, max : Double) : Double +; https://docs.microsoft.com/qsharp/api/qsharp/microsoft.quantum.random.drawrandomdouble +define dllexport double @__quantum__qis__drawrandomdouble__body(double %min, double %max) { + %result = call double @quantum__qis__drawrandomdouble__body(double %min, double %max) + ret double %result +} + + + ;=============================================================================== ; quantum.qis conditional functions ; diff --git a/src/QirRuntime/lib/QSharpFoundation/qsharp__foundation__qis.hpp b/src/Qir/Runtime/lib/QSharpFoundation/qsharp__foundation__qis.hpp similarity index 94% rename from src/QirRuntime/lib/QSharpFoundation/qsharp__foundation__qis.hpp rename to src/Qir/Runtime/lib/QSharpFoundation/qsharp__foundation__qis.hpp index 3c15948463b..aa234b36170 100644 --- a/src/QirRuntime/lib/QSharpFoundation/qsharp__foundation__qis.hpp +++ b/src/Qir/Runtime/lib/QSharpFoundation/qsharp__foundation__qis.hpp @@ -27,8 +27,6 @@ namespace Quantum */ extern "C" { - QIR_SHARED_API void quantum__qis__message__body(QirString* qstr); // NOLINT - // Q# Math: QIR_SHARED_API bool quantum__qis__isnan__body(double d); // NOLINT QIR_SHARED_API double quantum__qis__infinity__body(); // NOLINT @@ -42,6 +40,7 @@ extern "C" QIR_SHARED_API double quantum__qis__ieeeremainder__body(double x, double y); // NOLINT QIR_SHARED_API int64_t quantum__qis__drawrandomint__body(int64_t minimum, int64_t maximum); // NOLINT + QIR_SHARED_API double quantum__qis__drawrandomdouble__body(double minimum, double maximum); // NOLINT // Q# ApplyIf: QIR_SHARED_API void quantum__qis__applyifelseintrinsic__body(RESULT*, QirCallable*, QirCallable*); // NOLINT diff --git a/src/QirRuntime/lib/Simulators/CMakeLists.txt b/src/Qir/Runtime/lib/Simulators/CMakeLists.txt similarity index 58% rename from src/QirRuntime/lib/Simulators/CMakeLists.txt rename to src/Qir/Runtime/lib/Simulators/CMakeLists.txt index abbceb8e16e..77d9ffb860d 100644 --- a/src/QirRuntime/lib/Simulators/CMakeLists.txt +++ b/src/Qir/Runtime/lib/Simulators/CMakeLists.txt @@ -8,15 +8,6 @@ set(includes "${public_includes}" ) - -#=============================================================================== -# Produce static lib for users to link directly to - -add_library(simulators STATIC ${source_files}) -target_include_directories(simulators PUBLIC ${includes}) -target_link_libraries(simulators ${CMAKE_DL_LIBS}) -target_compile_definitions(simulators PRIVATE EXPORT_QIR_API) - #=============================================================================== # Produce object lib we'll use to create a shared lib (so/dll) later on diff --git a/src/QirRuntime/lib/Simulators/FullstateSimulator.cpp b/src/Qir/Runtime/lib/Simulators/FullstateSimulator.cpp similarity index 100% rename from src/QirRuntime/lib/Simulators/FullstateSimulator.cpp rename to src/Qir/Runtime/lib/Simulators/FullstateSimulator.cpp diff --git a/src/QirRuntime/lib/Simulators/ToffoliSimulator.cpp b/src/Qir/Runtime/lib/Simulators/ToffoliSimulator.cpp similarity index 90% rename from src/QirRuntime/lib/Simulators/ToffoliSimulator.cpp rename to src/Qir/Runtime/lib/Simulators/ToffoliSimulator.cpp index db992d24ba3..bc3c94c3de4 100644 --- a/src/QirRuntime/lib/Simulators/ToffoliSimulator.cpp +++ b/src/Qir/Runtime/lib/Simulators/ToffoliSimulator.cpp @@ -8,8 +8,6 @@ #include "QSharpSimApi_I.hpp" #include "SimFactory.hpp" -#include "BitStates.hpp" - namespace Microsoft { namespace Quantum @@ -24,7 +22,7 @@ namespace Quantum // State of a qubit is represented by a bit in states indexed by qubit's id, // bits 0 and 1 correspond to |0> and |1> states respectively. - BitStates states; + std::vector states; // The clients should never attempt to derefenece the Result, so we'll use fake // pointers to avoid allocation and deallocation. @@ -67,7 +65,7 @@ namespace Quantum Qubit AllocateQubit() override { this->lastUsedId++; - this->states.ExtendToInclude(this->lastUsedId); + this->states.emplace_back(false); return reinterpret_cast(this->lastUsedId); } @@ -75,13 +73,15 @@ namespace Quantum { const long id = GetQubitId(qubit); assert(id <= this->lastUsedId); - assert(!this->states.IsBitSetAt(id)); + assert(!this->states.at(id)); + this->lastUsedId--; + this->states.pop_back(); } std::string QubitToString(Qubit qubit) override { const long id = GetQubitId(qubit); - return std::to_string(id) + ":" + (this->states.IsBitSetAt(id) ? "1" : "0"); + return std::to_string(id) + ":" + (this->states.at(id) ? "1" : "0"); } /// @@ -120,7 +120,7 @@ namespace Quantum /// void X(Qubit qubit) override { - this->states.FlipBitAt(GetQubitId(qubit)); + this->states.at(GetQubitId(qubit)).flip(); } void ControlledX(long numControls, Qubit* const controls, Qubit qubit) override @@ -128,7 +128,7 @@ namespace Quantum bool allControlsSet = true; for (long i = 0; i < numControls; i++) { - if (!this->states.IsBitSetAt(GetQubitId(controls[i]))) + if (!this->states.at(GetQubitId(controls[i]))) { allControlsSet = false; break; @@ -137,7 +137,7 @@ namespace Quantum if (allControlsSet) { - this->states.FlipBitAt(GetQubitId(qubit)); + this->states.at(GetQubitId(qubit)).flip(); } } @@ -153,7 +153,7 @@ namespace Quantum } if (bases[i] == PauliId_Z) { - odd ^= (this->states.IsBitSetAt(GetQubitId(targets[i]))); + odd ^= (this->states.at(GetQubitId(targets[i]))); } } return odd ? one : zero; diff --git a/src/QirRuntime/lib/Simulators/setup.cpp b/src/Qir/Runtime/lib/Simulators/setup.cpp similarity index 100% rename from src/QirRuntime/lib/Simulators/setup.cpp rename to src/Qir/Runtime/lib/Simulators/setup.cpp diff --git a/src/QirRuntime/lib/Tracer/CMakeLists.txt b/src/Qir/Runtime/lib/Tracer/CMakeLists.txt similarity index 76% rename from src/QirRuntime/lib/Tracer/CMakeLists.txt rename to src/Qir/Runtime/lib/Tracer/CMakeLists.txt index 4fb8034fd8e..a73cfeb28fd 100644 --- a/src/QirRuntime/lib/Tracer/CMakeLists.txt +++ b/src/Qir/Runtime/lib/Tracer/CMakeLists.txt @@ -1,6 +1,3 @@ -# build the utility lib for tracer's bridge -compile_from_qir(tracer-bridge tracer-bridge) - # build the native part of the tracer set(source_files "tracer-qis.cpp" @@ -12,14 +9,9 @@ set(includes "${PROJECT_SOURCE_DIR}/lib/QIR" ) -add_library(tracer STATIC ${source_files}) -target_include_directories(tracer PUBLIC ${includes}) -add_dependencies(tracer tracer-bridge) -target_compile_definitions(tracer PRIVATE EXPORT_QIR_API) - # Produce object lib we'll use to create a shared lib (so/dll) later on add_library(tracer-obj OBJECT ${source_files}) -target_source_from_qir_obj(tracer-obj tracer-bridge) +target_source_from_qir(tracer-obj tracer-bridge.ll) target_include_directories(tracer-obj PUBLIC ${includes}) set_property(TARGET tracer-obj PROPERTY POSITION_INDEPENDENT_CODE ON) target_compile_definitions(tracer-obj PRIVATE EXPORT_QIR_API) @@ -35,6 +27,7 @@ target_link_libraries(Microsoft.Quantum.Qir.Tracer "-L${CMAKE_BINARY_DIR}/lib/QIR" -lMicrosoft.Quantum.Qir.Runtime ) +add_dependencies(Microsoft.Quantum.Qir.QSharp.Foundation Microsoft.Quantum.Qir.Runtime) target_include_directories(Microsoft.Quantum.Qir.Tracer PUBLIC ${includes}) target_compile_definitions(Microsoft.Quantum.Qir.Tracer PRIVATE EXPORT_QIR_API) diff --git a/src/QirRuntime/lib/Tracer/README.md b/src/Qir/Runtime/lib/Tracer/README.md similarity index 100% rename from src/QirRuntime/lib/Tracer/README.md rename to src/Qir/Runtime/lib/Tracer/README.md diff --git a/src/QirRuntime/lib/Tracer/layering_example.png b/src/Qir/Runtime/lib/Tracer/layering_example.png similarity index 100% rename from src/QirRuntime/lib/Tracer/layering_example.png rename to src/Qir/Runtime/lib/Tracer/layering_example.png diff --git a/src/QirRuntime/lib/Tracer/tracer-bridge.ll b/src/Qir/Runtime/lib/Tracer/tracer-bridge.ll similarity index 100% rename from src/QirRuntime/lib/Tracer/tracer-bridge.ll rename to src/Qir/Runtime/lib/Tracer/tracer-bridge.ll diff --git a/src/QirRuntime/lib/Tracer/tracer-qis.cpp b/src/Qir/Runtime/lib/Tracer/tracer-qis.cpp similarity index 100% rename from src/QirRuntime/lib/Tracer/tracer-qis.cpp rename to src/Qir/Runtime/lib/Tracer/tracer-qis.cpp diff --git a/src/QirRuntime/lib/Tracer/tracer.cpp b/src/Qir/Runtime/lib/Tracer/tracer.cpp similarity index 100% rename from src/QirRuntime/lib/Tracer/tracer.cpp rename to src/Qir/Runtime/lib/Tracer/tracer.cpp diff --git a/src/QirRuntime/lib/Tracer/tracer.hpp b/src/Qir/Runtime/lib/Tracer/tracer.hpp similarity index 100% rename from src/QirRuntime/lib/Tracer/tracer.hpp rename to src/Qir/Runtime/lib/Tracer/tracer.hpp diff --git a/src/QirRuntime/prerequisites.ps1 b/src/Qir/Runtime/prerequisites.ps1 similarity index 64% rename from src/QirRuntime/prerequisites.ps1 rename to src/Qir/Runtime/prerequisites.ps1 index 17b9b0633ca..72ae1b5079c 100644 --- a/src/QirRuntime/prerequisites.ps1 +++ b/src/Qir/Runtime/prerequisites.ps1 @@ -1,11 +1,12 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. -if ($Env:ENABLE_QIRRUNTIME -eq "true") { - if (($IsWindows) -or ((Test-Path Env:AGENT_OS) -and ($Env:AGENT_OS.StartsWith("Win"))) -and - !(Get-Command clang -ErrorAction SilentlyContinue)) { - choco install llvm - choco install ninja +if ($Env:ENABLE_QIRRUNTIME -ne "false") { + if (($IsWindows) -or ((Test-Path Env:AGENT_OS) -and ($Env:AGENT_OS.StartsWith("Win")))) { + if (!(Get-Command clang -ErrorAction SilentlyContinue)) { + choco install llvm + choco install ninja + } } elseif ($IsMacOS) { brew install ninja } else { diff --git a/src/QirRuntime/public/CoreTypes.hpp b/src/Qir/Runtime/public/CoreTypes.hpp similarity index 100% rename from src/QirRuntime/public/CoreTypes.hpp rename to src/Qir/Runtime/public/CoreTypes.hpp diff --git a/src/QirRuntime/public/QSharpSimApi_I.hpp b/src/Qir/Runtime/public/QSharpSimApi_I.hpp similarity index 100% rename from src/QirRuntime/public/QSharpSimApi_I.hpp rename to src/Qir/Runtime/public/QSharpSimApi_I.hpp diff --git a/src/QirRuntime/public/QirContext.hpp b/src/Qir/Runtime/public/QirContext.hpp similarity index 100% rename from src/QirRuntime/public/QirContext.hpp rename to src/Qir/Runtime/public/QirContext.hpp diff --git a/src/QirRuntime/public/QirRuntime.hpp b/src/Qir/Runtime/public/QirRuntime.hpp similarity index 92% rename from src/QirRuntime/public/QirRuntime.hpp rename to src/Qir/Runtime/public/QirRuntime.hpp index eedcdf659b4..c4236ff0e1a 100644 --- a/src/QirRuntime/public/QirRuntime.hpp +++ b/src/Qir/Runtime/public/QirRuntime.hpp @@ -5,6 +5,7 @@ #include #include // for va_list +#include #include "CoreTypes.hpp" #include "QirTypes.hpp" @@ -56,11 +57,14 @@ extern "C" // ------------------------------------------------------------------------ // Allocate a block of memory on the heap. - QIR_SHARED_API char* quantum__rt__heap_alloc(int size); // NOLINT + QIR_SHARED_API char* quantum__rt__heap_alloc(uint64_t size); // NOLINT // Release a block of allocated heap memory. QIR_SHARED_API void quantum__rt__heap_free(char* buffer); // NOLINT + // Returns a pointer to the malloc-allocated block. + QIR_SHARED_API char* quantum__rt__memory_allocate(uint64_t size); // NOLINT + // Fail the computation with the given error message. QIR_SHARED_API void quantum__rt__fail(QirString* msg); // NOLINT @@ -78,9 +82,8 @@ extern "C" // becomes 0. The behavior is undefined if the reference count becomes negative. QIR_SHARED_API void quantum__rt__result_update_reference_count(RESULT*, int32_t); // NOLINT - // Not in the QIR spec right now - QIR_SHARED_API RESULT* quantum__rt__result_one(); // NOLINT - QIR_SHARED_API RESULT* quantum__rt__result_zero(); // NOLINT + QIR_SHARED_API RESULT* quantum__rt__result_get_one(); // NOLINT + QIR_SHARED_API RESULT* quantum__rt__result_get_zero(); // NOLINT // ------------------------------------------------------------------------ // Tuples @@ -160,7 +163,6 @@ extern "C" // Initializes the callable with the provided function table and capture tuple. The capture tuple pointer // should be null if there is no capture. typedef void (*t_CallableEntry)(PTuple, PTuple, PTuple); // NOLINT - typedef void (*t_CaptureCallback)(PTuple, int64_t); // NOLINT QIR_SHARED_API QirCallable* quantum__rt__callable_create(t_CallableEntry*, t_CaptureCallback*, PTuple); // NOLINT // Adds the given integer value to the reference count for the callable. Deallocates the callable if the reference @@ -184,9 +186,9 @@ extern "C" QIR_SHARED_API void quantum__rt__callable_make_controlled(QirCallable*); // NOLINT // Invokes the function at the given index in the memory management table of the callable with the capture tuple and - // the given 64-bit integer. Does nothing if if the memory management table pointer or the function pointer at that + // the given 32-bit integer. Does nothing if the memory management table pointer or the function pointer at that // index is null. - QIR_SHARED_API void quantum__rt__callable_memory_management(int32_t, QirCallable*, int64_t); // NOLINT + QIR_SHARED_API void quantum__rt__callable_memory_management(int32_t, QirCallable*, int32_t); // NOLINT // ------------------------------------------------------------------------ // Strings @@ -228,6 +230,14 @@ extern "C" // Returns a string representation of the range. QIR_SHARED_API QirString* quantum__rt__range_to_string(const QirRange&); // NOLINT + // Returns a pointer to an array that contains a null-terminated sequence of characters + // (i.e., a C-string) representing the current value of the string object. + QIR_SHARED_API const char* quantum__rt__string_get_data(QirString* str); // NOLINT + + // Returns the length of the string, in terms of bytes. + // http://www.cplusplus.com/reference/string/string/size/ + QIR_SHARED_API uint32_t quantum__rt__string_get_length(QirString* str); // NOLINT + // Returns a string representation of the big integer. // TODO QIR_SHARED_API QirString* quantum__rt__bigint_to_string(QirBigInt*); // NOLINT @@ -293,4 +303,13 @@ extern "C" // Returns true if the first big integer is greater than or equal to the second, false otherwise. // TODO QIR_SHARED_API bool quantum__rt__bigint_greater_eq(QirBigInt*, QirBigInt*); // NOLINT -} \ No newline at end of file +} + +// To do: consider extracting to QirRuntimeOut.hpp +namespace Microsoft // Replace with `namespace Microsoft::Quantum` after migration to C++17. +{ +namespace Quantum +{ + QIR_SHARED_API std::ostream& SetOutputStream(std::ostream & newOStream); +} // namespace Microsoft +} // namespace Quantum diff --git a/src/QirRuntime/public/QirRuntimeApi_I.hpp b/src/Qir/Runtime/public/QirRuntimeApi_I.hpp similarity index 100% rename from src/QirRuntime/public/QirRuntimeApi_I.hpp rename to src/Qir/Runtime/public/QirRuntimeApi_I.hpp diff --git a/src/QirRuntime/public/QirTypes.hpp b/src/Qir/Runtime/public/QirTypes.hpp similarity index 94% rename from src/QirRuntime/public/QirTypes.hpp rename to src/Qir/Runtime/public/QirTypes.hpp index 6b144975346..4809def635b 100644 --- a/src/QirRuntime/public/QirTypes.hpp +++ b/src/Qir/Runtime/public/QirTypes.hpp @@ -61,9 +61,9 @@ struct QIR_SHARED_API QirString using PTuple = char*; struct QIR_SHARED_API QirTupleHeader { - int32_t refCount = 0; + int refCount = 0; int32_t aliasCount = 0; // used to enable copy elision, see the QIR specifications for details - int32_t tupleSize = 0; // when creating the tuple, must be set to the size of the tuple's data buffer + int32_t tupleSize = 0; // when creating the tuple, must be set to the size of the tuple's data buffer (in bytes) // flexible array member, must be last in the struct char data[]; @@ -121,7 +121,7 @@ static_assert( QirCallable ======================================================================================================================*/ typedef void (*t_CallableEntry)(PTuple, PTuple, PTuple); -typedef void (*t_CaptureCallback)(PTuple, int64_t); +typedef void (*t_CaptureCallback)(PTuple, int32_t); struct QIR_SHARED_API QirCallable { static int constexpr Adjoint = 1; @@ -171,5 +171,5 @@ struct QIR_SHARED_API QirCallable void Invoke(); // a shortcut to invoke a callable with no arguments and Unit result void ApplyFunctor(int functor); - void InvokeCaptureCallback(int index, int64_t parameter); + void InvokeCaptureCallback(int32_t index, int32_t parameter); }; \ No newline at end of file diff --git a/src/QirRuntime/public/SimFactory.hpp b/src/Qir/Runtime/public/SimFactory.hpp similarity index 82% rename from src/QirRuntime/public/SimFactory.hpp rename to src/Qir/Runtime/public/SimFactory.hpp index f8ab837443e..14128657262 100644 --- a/src/QirRuntime/public/SimFactory.hpp +++ b/src/Qir/Runtime/public/SimFactory.hpp @@ -18,6 +18,5 @@ namespace Quantum // Full State Simulator QIR_SHARED_API std::unique_ptr CreateFullstateSimulator(); - QIR_SHARED_API std::ostream& SetOutputStream(std::ostream& newOStream); } // namespace Quantum } // namespace Microsoft \ No newline at end of file diff --git a/src/QirRuntime/public/TracerTypes.hpp b/src/Qir/Runtime/public/TracerTypes.hpp similarity index 100% rename from src/QirRuntime/public/TracerTypes.hpp rename to src/Qir/Runtime/public/TracerTypes.hpp diff --git a/src/QirRuntime/qir.png b/src/Qir/Runtime/qir.png similarity index 100% rename from src/QirRuntime/qir.png rename to src/Qir/Runtime/qir.png diff --git a/src/Qir/Runtime/test-qir-runtime.ps1 b/src/Qir/Runtime/test-qir-runtime.ps1 new file mode 100644 index 00000000000..5f24e3f7cdb --- /dev/null +++ b/src/Qir/Runtime/test-qir-runtime.ps1 @@ -0,0 +1,8 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +. (Join-Path $PSScriptRoot .. qir-utils.ps1) + +if (-not (Test-CTest (Join-Path $PSScriptRoot build $Env:BUILD_CONFIGURATION unittests) "QIR Runtime")) { + throw "At least one project failed testing. Check the logs." +} diff --git a/src/Qir/Runtime/unittests/CMakeLists.txt b/src/Qir/Runtime/unittests/CMakeLists.txt new file mode 100644 index 00000000000..40c41776d2a --- /dev/null +++ b/src/Qir/Runtime/unittests/CMakeLists.txt @@ -0,0 +1,30 @@ +include(unit_test_include) + +#============================================================================== +# produce the unit tests binary: qir-runtime-unittests.exe +# +add_executable(qir-runtime-unittests + driver.cpp + QirRuntimeTests.cpp + ToffoliTests.cpp + TracerTests.cpp + $ + $ + $ + $ + $ +) + +target_include_directories(qir-runtime-unittests PUBLIC + "${PROJECT_SOURCE_DIR}/../Common/externals/catch2" + ${public_includes} + ${common_includes} + "${PROJECT_SOURCE_DIR}/lib/QIR" + "${PROJECT_SOURCE_DIR}/lib/QSharpFoundation" + "${PROJECT_SOURCE_DIR}/lib/QSharpCore" + "${PROJECT_SOURCE_DIR}/lib/Tracer" +) +target_link_libraries(qir-runtime-unittests ${CMAKE_DL_LIBS}) +target_compile_definitions(qir-runtime-unittests PRIVATE EXPORT_QIR_API) +install(TARGETS qir-runtime-unittests RUNTIME DESTINATION "${CMAKE_BINARY_DIR}/bin") +add_unit_test(qir-runtime-unittests) diff --git a/src/QirRuntime/test/unittests/QirRuntimeTests.cpp b/src/Qir/Runtime/unittests/QirRuntimeTests.cpp similarity index 96% rename from src/QirRuntime/test/unittests/QirRuntimeTests.cpp rename to src/Qir/Runtime/unittests/QirRuntimeTests.cpp index d47c26fafcb..d76f37725b3 100644 --- a/src/QirRuntime/test/unittests/QirRuntimeTests.cpp +++ b/src/Qir/Runtime/unittests/QirRuntimeTests.cpp @@ -1,1081 +1,1095 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "catch.hpp" - -#include -#include // for memcpy -#include -#include -#include - -#include "QirTypes.hpp" -#include "qsharp__foundation__qis.hpp" -#include "qsharp__core__qis.hpp" -#include "QirRuntime.hpp" - -#include "BitStates.hpp" -#include "QirContext.hpp" -#include "SimulatorStub.hpp" - -using namespace Microsoft::Quantum; - -struct ResultsReferenceCountingTestQAPI : public SimulatorStub -{ - int lastId = 1; - const int maxResults; - BitStates allocated; - - static int GetResultId(Result r) - { - return static_cast(reinterpret_cast(r)); - } - - ResultsReferenceCountingTestQAPI(int maxResults) - : maxResults(maxResults + 2) - { - allocated.ExtendToInclude(maxResults); - } - - Result Measure(long, PauliId[], long, Qubit[]) override - { - assert(this->lastId < this->maxResults); - this->lastId++; - this->allocated.SetBitAt(this->lastId); - return reinterpret_cast(this->lastId); - } - Result UseZero() override - { - return reinterpret_cast(0); - } - Result UseOne() override - { - return reinterpret_cast(1); - } - void ReleaseResult(Result result) override - { - const int id = GetResultId(result); - INFO(id); - REQUIRE(this->allocated.IsBitSetAt(id)); - this->allocated.FlipBitAt(id); - } - bool AreEqualResults(Result r1, Result r2) override - { - return (r1 == r2); - } - - bool HaveResultsInFlight() const - { - return this->allocated.IsAny(); - } -}; -TEST_CASE("Results: comparison and reference counting", "[qir_support]") -{ - std::unique_ptr qapi = std::make_unique(3); - QirContextScope qirctx(qapi.get()); - - Result r1 = qapi->Measure(0, nullptr, 0, nullptr); // we don't need real qubits for this test - Result r2 = qapi->Measure(0, nullptr, 0, nullptr); - REQUIRE(quantum__rt__result_equal(r1, r1)); - REQUIRE(!quantum__rt__result_equal(r1, r2)); - - // release result that has never been shared, the test QAPI will verify double release - quantum__rt__result_update_reference_count(r2, -1); - - // share a result a few times - quantum__rt__result_update_reference_count(r1, 2); - - Result r3 = qapi->Measure(0, nullptr, 0, nullptr); - - // release shared result, the test QAPI will verify double release - quantum__rt__result_update_reference_count(r1, -3); // one release for shared and for the original allocation - - REQUIRE(qapi->HaveResultsInFlight()); // r3 should be still alive - quantum__rt__result_update_reference_count(r3, -1); - - REQUIRE(!qapi->HaveResultsInFlight()); // no leaks -} - -TEST_CASE("Arrays: one dimensional", "[qir_support]") -{ - QirContextScope qirctx(nullptr); - QirArray* a = quantum__rt__array_create_1d(sizeof(char), 5); - - memcpy(a->buffer, "Hello", 5); - REQUIRE(*quantum__rt__array_get_element_ptr_1d(a, 4) == 'o'); - REQUIRE(quantum__rt__array_get_dim(a) == 1); - REQUIRE(quantum__rt__array_get_size(a, 0) == 5); - - QirArray* b = new QirArray(1, sizeof(char)); - *quantum__rt__array_get_element_ptr_1d(b, 0) = '!'; - - QirArray* ab = quantum__rt__array_concatenate(a, b); - REQUIRE(quantum__rt__array_get_size(ab, 0) == 6); - REQUIRE(*quantum__rt__array_get_element_ptr_1d(ab, 4) == 'o'); - REQUIRE(*quantum__rt__array_get_element_ptr_1d(ab, 5) == '!'); - - quantum__rt__array_update_reference_count(a, -1); - quantum__rt__array_update_reference_count(b, -1); - quantum__rt__array_update_reference_count(ab, -1); -} - -TEST_CASE("Arrays: multiple dimensions", "[qir_support]") -{ - QirContextScope qirctx(nullptr); - - const int64_t count = 5 * 3 * 4; // 60 - QirArray* a = quantum__rt__array_create(sizeof(int), 3, (int64_t)5, (int64_t)3, (int64_t)4); - REQUIRE(quantum__rt__array_get_dim(a) == 3); - REQUIRE(quantum__rt__array_get_size(a, 0) == 5); - REQUIRE(quantum__rt__array_get_size(a, 1) == 3); - REQUIRE(quantum__rt__array_get_size(a, 2) == 4); - - std::vector data(count, 0); - for (int i = 0; i < count; i++) - { - data[i] = i; - } - // 000 001 002 003 | 010 011 012 013 | 020 021 022 023 -- [0 - 11] - // 100 101 102 103 | 110 111 112 113 | 120 121 122 123 -- [12 - 23] - // ... [24 - 35] - // ... [36 - 47] - // 400 401 402 403 | 410 411 412 413 | 420 421 422 423 -- [48 - 59] - memcpy(a->buffer, reinterpret_cast(data.data()), count * sizeof(int)); - REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(a, 0, 0, 1))) == 1); - REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(a, 0, 1, 0))) == 4); - REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(a, 1, 0, 0))) == 12); - REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(a, 4, 2, 3))) == 59); - - QirArray* b = quantum__rt__array_copy(a, true /*force*/); - *(reinterpret_cast(quantum__rt__array_get_element_ptr(b, 1, 2, 3))) = 42; - REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(a, 1, 2, 3))) == 23); - - quantum__rt__array_update_reference_count(a, -1); - quantum__rt__array_update_reference_count(b, -1); -} - -TEST_CASE("Arrays: copy elision", "[qir_support]") -{ - QirContextScope qirctx(nullptr); - - QirArray* copy = quantum__rt__array_copy(nullptr, true /*force*/); - CHECK(copy == nullptr); - - QirArray* a = quantum__rt__array_create_1d(sizeof(char), 5); - // the `a` array contains garbage but for this test we don't care - - // no aliases for the array, copy should be elided unless enforced - copy = quantum__rt__array_copy(a, false /*force*/); - CHECK(a == copy); - quantum__rt__array_update_reference_count(copy, -1); - - // single alias for the array, but copy enforced - copy = quantum__rt__array_copy(a, true /*force*/); - CHECK(a != copy); - quantum__rt__array_update_reference_count(copy, -1); - - // existing aliases for the array -- cannot elide copy - quantum__rt__array_update_alias_count(a, 1); - copy = quantum__rt__array_copy(a, false /*force*/); - CHECK(a != copy); - quantum__rt__array_update_reference_count(copy, -1); - - quantum__rt__array_update_reference_count(a, -1); -} - -TEST_CASE("Arrays: empty", "[qir_support]") -{ - QirContextScope qirctx(nullptr); - - QirArray* b = quantum__rt__array_create(sizeof(int), 3, (int64_t)4, (int64_t)0, (int64_t)3); - REQUIRE(quantum__rt__array_get_dim(b) == 3); - REQUIRE(quantum__rt__array_get_size(b, 0) == 4); - REQUIRE(quantum__rt__array_get_size(b, 1) == 0); - REQUIRE(quantum__rt__array_get_size(b, 2) == 3); - REQUIRE(b->buffer == nullptr); - quantum__rt__array_update_reference_count(b, -1); - - QirArray* a = quantum__rt__array_create_1d(sizeof(char), 0); - REQUIRE(quantum__rt__array_get_dim(a) == 1); - REQUIRE(quantum__rt__array_get_size(a, 0) == 0); - REQUIRE(a->buffer == nullptr); - - QirArray* a1 = quantum__rt__array_copy(a, true /*force*/); - REQUIRE(quantum__rt__array_get_dim(a1) == 1); - REQUIRE(quantum__rt__array_get_size(a1, 0) == 0); - REQUIRE(a1->buffer == nullptr); - quantum__rt__array_update_reference_count(a1, -1); - - QirArray* c = quantum__rt__array_create_1d(sizeof(char), 5); - memcpy(c->buffer, "hello", 5); - QirArray* ac = quantum__rt__array_concatenate(a, c); - REQUIRE(quantum__rt__array_get_size(ac, 0) == 5); - QirArray* ca = quantum__rt__array_concatenate(c, a); - REQUIRE(quantum__rt__array_get_size(ca, 0) == 5); - - quantum__rt__array_update_reference_count(a, -1); - quantum__rt__array_update_reference_count(ac, -1); - quantum__rt__array_update_reference_count(ca, -1); -} - -TEST_CASE("Arrays: check the slice range", "[qir_support]") -{ - QirContextScope qirctx(nullptr); - - const int64_t dim0 = 5; - const int64_t dim1 = 6; - QirArray* a = quantum__rt__array_create(sizeof(int), 2, dim0, dim1); - QirArray* slice = nullptr; - - // invalid range - CHECK_THROWS(quantum__rt__array_slice(a, 0, {0, 0, 0})); - - // violated bounds - CHECK_THROWS(quantum__rt__array_slice(a, 0, {dim0, 1, dim0})); - CHECK_THROWS(quantum__rt__array_slice(a, 1, {0, 1, dim1})); - CHECK_THROWS(quantum__rt__array_slice(a, 0, {-1, 1, dim0 - 1})); - - CHECK_THROWS(quantum__rt__array_slice(a, 0, {dim0, -1, dim0})); - CHECK_THROWS(quantum__rt__array_slice(a, 1, {dim1, -1, 0})); - CHECK_THROWS(quantum__rt__array_slice(a, 0, {dim0 - 1, -1, -1})); - - CHECK_THROWS(quantum__rt__array_slice(a, 0, {dim0, 3, dim0})); - CHECK_THROWS(quantum__rt__array_slice(a, 1, {0, 3, dim1 + 2})); - CHECK_THROWS(quantum__rt__array_slice(a, 0, {-1, 3, dim0 - 1})); - - CHECK_THROWS(quantum__rt__array_slice(a, 0, {dim0, -3, dim0})); - CHECK_THROWS(quantum__rt__array_slice(a, 1, {dim1, -3, 0})); - CHECK_THROWS(quantum__rt__array_slice(a, 0, {dim0 - 1, -3, -3})); - - // empty range should produce empty array - slice = quantum__rt__array_slice(a, 0, {dim0 - 1, 1, 0}); - REQUIRE(quantum__rt__array_get_size(slice, 0) == 0); - REQUIRE(quantum__rt__array_get_size(slice, 1) == dim1); - quantum__rt__array_update_reference_count(slice, -1); - - slice = quantum__rt__array_slice(a, 1, {0, -1, dim0 - 1}); - REQUIRE(quantum__rt__array_get_size(slice, 0) == dim0); - REQUIRE(quantum__rt__array_get_size(slice, 1) == 0); - quantum__rt__array_update_reference_count(slice, -1); - - quantum__rt__array_update_reference_count(a, -1); -} - -TEST_CASE("Arrays: slice of 1D array", "[qir_support]") -{ - QirContextScope qirctx(nullptr); - - const int64_t dim = 5; - QirArray* a = quantum__rt__array_create_1d(sizeof(char), dim); - memcpy(a->buffer, "01234", 5); - QirArray* slice = nullptr; - - // even if slice results in a single value, it's still an array - slice = quantum__rt__array_slice(a, 0, {1, 2 * dim, dim}); - REQUIRE(quantum__rt__array_get_size(slice, 0) == 1); - REQUIRE(*quantum__rt__array_get_element_ptr_1d(slice, 0) == '1'); - quantum__rt__array_update_reference_count(slice, -1); - - // if the range covers the whole array, it's effectively a copy - slice = quantum__rt__array_slice(a, 0, {0, 1, dim - 1}); - REQUIRE(quantum__rt__array_get_size(slice, 0) == dim); - REQUIRE(*quantum__rt__array_get_element_ptr_1d(slice, 0) == '0'); - REQUIRE(*quantum__rt__array_get_element_ptr(slice, 4) == '4'); - quantum__rt__array_update_reference_count(slice, -1); - - // disconnected slice (also check that the end of range can be above bounds as long as the generated sequence is - // within them) - slice = quantum__rt__array_slice(a, 0, {0, 4, dim + 1}); - REQUIRE(quantum__rt__array_get_size(slice, 0) == 2); - REQUIRE(*quantum__rt__array_get_element_ptr_1d(slice, 0) == '0'); - REQUIRE(*quantum__rt__array_get_element_ptr_1d(slice, 1) == '4'); - quantum__rt__array_update_reference_count(slice, -1); - - quantum__rt__array_update_reference_count(a, -1); -} - -TEST_CASE("Arrays: reversed slice of 1D array", "[qir_support]") -{ - QirContextScope qirctx(nullptr); - const int64_t dim = 5; - QirArray* a = quantum__rt__array_create_1d(sizeof(char), dim); - memcpy(a->buffer, "01234", 5); - QirArray* slice = nullptr; - - // even if slice results in a single value, it's still an array - slice = quantum__rt__array_slice(a, 0, {1, -dim, 0}); - REQUIRE(quantum__rt__array_get_size(slice, 0) == 1); - REQUIRE(*quantum__rt__array_get_element_ptr_1d(slice, 0) == '1'); - quantum__rt__array_update_reference_count(slice, -1); - - // reversed slices are alwayes disconnected - slice = quantum__rt__array_slice(a, 0, {dim - 1, -2, 0}); - REQUIRE(quantum__rt__array_get_size(slice, 0) == 3); - REQUIRE(*quantum__rt__array_get_element_ptr_1d(slice, 0) == '4'); - REQUIRE(*quantum__rt__array_get_element_ptr_1d(slice, 1) == '2'); - REQUIRE(*quantum__rt__array_get_element_ptr_1d(slice, 2) == '0'); - quantum__rt__array_update_reference_count(slice, -1); - - quantum__rt__array_update_reference_count(a, -1); -} - -TEST_CASE("Arrays: slice of 3D array", "[qir_support]") -{ - QirContextScope qirctx(nullptr); - - const int32_t dims = 3; - const int64_t dim0 = 5; - const int64_t dim1 = 3; - const int64_t dim2 = 4; - - QirArray* a = quantum__rt__array_create(sizeof(int), dims, dim0, dim1, dim2); - QirArray* slice = nullptr; - - const int64_t count = dim0 * dim1 * dim2; // 60 - std::vector data(count, 0); - for (int i = 0; i < count; i++) - { - data[i] = i; - } - // indexes -- values - // 000 001 002 003 | 010 011 012 013 | 020 021 022 023 -- [0 - 11] - // 100 101 102 103 | 110 111 112 113 | 120 121 122 123 -- [12 - 23] - // ... [24 - 35] - // ... [36 - 47] - // 400 401 402 403 | 410 411 412 413 | 420 421 422 423 -- [48 - 59] - memcpy(a->buffer, reinterpret_cast(data.data()), count * sizeof(int)); - REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(a, 1, 0, 0))) == 12); - REQUIRE( - *(reinterpret_cast(quantum__rt__array_get_element_ptr(a, dim0 - 1, dim1 - 1, dim2 - 1))) == count - 1); - - // if the range covers the whole dimension, it's effectively a copy - slice = quantum__rt__array_slice(a, 1, {0, 1, dim1 - 1}); - REQUIRE(quantum__rt__array_get_dim(slice) == dims); - REQUIRE(quantum__rt__array_get_size(slice, 0) == dim0); - REQUIRE(quantum__rt__array_get_size(slice, 1) == dim1); - REQUIRE(quantum__rt__array_get_size(slice, 2) == dim2); - REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 1, 0, 0))) == 12); - REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 4, 2, 3))) == 59); - quantum__rt__array_update_reference_count(slice, -1); - - // if the range consists of a single point, the slice still has the same dimensions - slice = quantum__rt__array_slice(a, 1, {1, 2 * dim1, dim1}); // items with second index = 1 - REQUIRE(quantum__rt__array_get_dim(slice) == dims); - REQUIRE(quantum__rt__array_get_size(slice, 0) == dim0); - REQUIRE(quantum__rt__array_get_size(slice, 1) == 1); - REQUIRE(quantum__rt__array_get_size(slice, 2) == dim2); - REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 0, 0, 0))) == 4); - REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 4, 0, 3))) == 55); - quantum__rt__array_update_reference_count(slice, -1); - - // slice on 0 dimension - slice = quantum__rt__array_slice(a, 0, {1, 1, 3}); // items with first index = 1, 2 or 3 - REQUIRE(quantum__rt__array_get_dim(slice) == dims); - REQUIRE(quantum__rt__array_get_size(slice, 0) == 3); - REQUIRE(quantum__rt__array_get_size(slice, 1) == dim1); - REQUIRE(quantum__rt__array_get_size(slice, 2) == dim2); - REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 0, 0, 0))) == 12); - REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 2, 2, 3))) == 47); - quantum__rt__array_update_reference_count(slice, -1); - - // slice on last dimension, expected result: - // indexes -- values - // 000 001 | 010 011 | 020 021 -- [ 1 2 | 5 6 | 9 10] - // 100 101 | 110 111 | 120 121 -- [13 14 | 17 18 | 21 22] - // ... [25 ... ] - // ... [37 ... ] - // 400 401 | 410 411 | 420 421 -- [49 50 | 53 54 | 57 58] - slice = quantum__rt__array_slice(a, 2, {1, 1, 2}); // items with last index = 1 or 2 - REQUIRE(quantum__rt__array_get_dim(slice) == dims); - REQUIRE(quantum__rt__array_get_size(slice, 0) == dim0); - REQUIRE(quantum__rt__array_get_size(slice, 1) == dim1); - REQUIRE(quantum__rt__array_get_size(slice, 2) == 2); - REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 0, 0, 0))) == 1); - REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 0, 2, 1))) == 10); - REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 1, 1, 1))) == 18); - REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 4, 2, 1))) == 58); - quantum__rt__array_update_reference_count(slice, -1); - - // slice on sparse range in 0 dimension (also check that the end of range can be above bounds as long as the - // generated sequence is within them) - slice = quantum__rt__array_slice(a, 0, {0, 3, dim0}); // items with first index = 0 or 3 - REQUIRE(quantum__rt__array_get_dim(slice) == dims); - REQUIRE(quantum__rt__array_get_size(slice, 0) == 2); - REQUIRE(quantum__rt__array_get_size(slice, 1) == dim1); - REQUIRE(quantum__rt__array_get_size(slice, 2) == dim2); - REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 0, 0, 0))) == 0); - REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 1, 2, 3))) == 47); - quantum__rt__array_update_reference_count(slice, -1); - - // slice on sparse range in the middle dimension - slice = quantum__rt__array_slice(a, 1, {0, 2, 2}); // items with second index = 0 or 2 - REQUIRE(quantum__rt__array_get_dim(slice) == dims); - REQUIRE(quantum__rt__array_get_size(slice, 0) == dim0); - REQUIRE(quantum__rt__array_get_size(slice, 1) == 2); - REQUIRE(quantum__rt__array_get_size(slice, 2) == dim2); - REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 0, 0, 0))) == 0); - REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 4, 1, 3))) == 59); - quantum__rt__array_update_reference_count(slice, -1); - - // slice on sparse range in the last dimension - // indexes -- values - // 000 001 | 010 011 | 020 021 -- [01 03 | 05 07 | 09 11] - // 100 101 | 110 111 | 120 121 -- [13 15 | 17 19 | 21 23] - // ... -- [25 ... ] - // ... -- [37 ... ] - // 400 401 | 410 411 | 420 421 -- [49 51 | 53 55 | 57 59] - slice = quantum__rt__array_slice(a, 2, {1, 2, 3}); // items with last index = 1 or 3 (all odd numbers) - REQUIRE(quantum__rt__array_get_dim(slice) == dims); - REQUIRE(quantum__rt__array_get_size(slice, 0) == dim0); - REQUIRE(quantum__rt__array_get_size(slice, 1) == dim1); - REQUIRE(quantum__rt__array_get_size(slice, 2) == 2); - REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 0, 0, 0))) == 1); - REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 0, 2, 1))) == 11); - REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 1, 1, 0))) == 17); - REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 4, 2, 1))) == 59); - quantum__rt__array_update_reference_count(slice, -1); - - quantum__rt__array_update_reference_count(a, -1); -} - -TEST_CASE("Arrays: reversed slice of 3D array", "[qir_support]") -{ - QirContextScope qirctx(nullptr); - - const int32_t dims = 3; - const int64_t dim0 = 5; - const int64_t dim1 = 3; - const int64_t dim2 = 4; - - QirArray* a = quantum__rt__array_create(sizeof(int), dims, dim0, dim1, dim2); - QirArray* slice = nullptr; - - const int64_t count = dim0 * dim1 * dim2; // 60 - std::vector data(count, 0); - for (int i = 0; i < count; i++) - { - data[i] = i; - } - // indexes -- values - // 000 001 002 003 | 010 011 012 013 | 020 021 022 023 -- [0 - 11] - // 100 101 102 103 | 110 111 112 113 | 120 121 122 123 -- [12 - 23] - // ... [24 - 35] - // ... [36 - 47] - // 400 401 402 403 | 410 411 412 413 | 420 421 422 423 -- [48 - 59] - memcpy(a->buffer, reinterpret_cast(data.data()), count * sizeof(int)); - REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(a, 1, 0, 0))) == 12); - REQUIRE( - *(reinterpret_cast(quantum__rt__array_get_element_ptr(a, dim0 - 1, dim1 - 1, dim2 - 1))) == count - 1); - - // if the range consists of a single point, the slice still has the same dimensions - slice = quantum__rt__array_slice(a, 1, {1, -dim1, 0}); // items with second index = 1 - REQUIRE(quantum__rt__array_get_dim(slice) == dims); - REQUIRE(quantum__rt__array_get_size(slice, 0) == dim0); - REQUIRE(quantum__rt__array_get_size(slice, 1) == 1); - REQUIRE(quantum__rt__array_get_size(slice, 2) == dim2); - REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 0, 0, 0))) == 4); - REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 4, 0, 3))) == 55); - quantum__rt__array_update_reference_count(slice, -1); - - // slice on dim0, expect the result to look like: - // indexes -- values - // 000 001 002 003 | 010 011 012 013 | 020 021 022 023 -- [36 - 47] - // 100 101 102 103 | 110 111 112 113 | 120 121 122 123 -- [24 - 35] - // 200 201 202 203 | 210 211 212 213 | 220 221 222 223 -- [12 - 23] - slice = quantum__rt__array_slice(a, 0, {dim0 - 2, -1, 1}); - REQUIRE(quantum__rt__array_get_dim(slice) == dims); - REQUIRE(quantum__rt__array_get_size(slice, 0) == 3); - REQUIRE(quantum__rt__array_get_size(slice, 1) == dim1); - REQUIRE(quantum__rt__array_get_size(slice, 2) == dim2); - REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 0, 0, 0))) == 36); - REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 2, 2, 3))) == 23); - quantum__rt__array_update_reference_count(slice, -1); - - // slice on last dimension, expect the result to look like: - // indexes -- values - // 000 001 | 010 011 | 020 021 -- [03 01 | 07 05 | 11 09] - // 100 101 | 110 111 | 120 121 -- [15 13 | 19 17 | 23 21] - // ... -- [27 ... ] - // ... -- [39 ... ] - // 400 401 | 410 411 | 420 421 -- [51 49 | 55 53 | 59 57] - slice = quantum__rt__array_slice(a, 2, {dim2 - 1, -2, 0}); // items with last index 3, 1 (all odd numbers) - REQUIRE(quantum__rt__array_get_dim(slice) == dims); - REQUIRE(quantum__rt__array_get_size(slice, 0) == dim0); - REQUIRE(quantum__rt__array_get_size(slice, 1) == dim1); - REQUIRE(quantum__rt__array_get_size(slice, 2) == 2); - REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 0, 0, 0))) == 3); - REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 0, 2, 1))) == 9); - REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 1, 1, 0))) == 19); - REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 4, 2, 1))) == 57); - quantum__rt__array_update_reference_count(slice, -1); -} - -TEST_CASE("Arrays: project of 3D array", "[qir_support]") -{ - QirContextScope qirctx(nullptr); - - const int32_t dims = 3; - const int64_t dim0 = 5; - const int64_t dim1 = 3; - const int64_t dim2 = 4; - - QirArray* a = quantum__rt__array_create(sizeof(int), dims, dim0, dim1, dim2); - QirArray* project = nullptr; - - const int64_t count = dim0 * dim1 * dim2; // 60 - std::vector data(count, 0); - for (int i = 0; i < count; i++) - { - data[i] = i; - } - // indexes -- values - // 000 001 002 003 | 010 011 012 013 | 020 021 022 023 -- [0 - 11] - // 100 101 102 103 | 110 111 112 113 | 120 121 122 123 -- [12 - 23] - // ... [24 - 35] - // ... [36 - 47] - // 400 401 402 403 | 410 411 412 413 | 420 421 422 423 -- [48 - 59] - memcpy(a->buffer, reinterpret_cast(data.data()), count * sizeof(int)); - REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(a, 1, 0, 0))) == 12); - REQUIRE( - *(reinterpret_cast(quantum__rt__array_get_element_ptr(a, dim0 - 1, dim1 - 1, dim2 - 1))) == count - 1); - - // project on 0 dimension, expected result: - // indexes -- values - // 00 01 02 03 | 10 11 12 13 | 20 21 22 23 -- [12 - 23] - project = quantum__rt__array_project(a, 0, 1); // items with first index = 1 - REQUIRE(quantum__rt__array_get_dim(project) == dims - 1); - REQUIRE(quantum__rt__array_get_size(project, 0) == dim1); - REQUIRE(quantum__rt__array_get_size(project, 1) == dim2); - REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(project, 0, 0))) == 12); - REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(project, 1, 1))) == 17); - REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(project, 2, 3))) == 23); - quantum__rt__array_update_reference_count(project, -1); - - // project on last dimension, expected result: - // indexes -- values - // 00 | 01 | 02 -- [02 06 10] - // 10 | 11 | 12 -- [14 18 22] - // ... -- [26 30 34] - // ... -- [38 42 46] - // 40 | 41 | 42 -- [50 54 58] - project = quantum__rt__array_project(a, 2, 2); // items with last index = 2 - REQUIRE(quantum__rt__array_get_dim(project) == dims - 1); - REQUIRE(quantum__rt__array_get_size(project, 0) == dim0); - REQUIRE(quantum__rt__array_get_size(project, 1) == dim1); - REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(project, 0, 0, 0))) == 2); - REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(project, 1, 1, 2))) == 18); - REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(project, 4, 2, 2))) == 58); - quantum__rt__array_update_reference_count(project, -1); - - quantum__rt__array_update_reference_count(a, -1); -} - -std::unordered_map& AllocatedStrings(); -TEST_CASE("Strings: reuse", "[qir_support]") -{ - QirContextScope qirctx(nullptr); - - QirString* a = quantum__rt__string_create("abc"); - QirString* b = quantum__rt__string_create("abc"); - QirString* c = quantum__rt__string_create("xyz"); - - REQUIRE(a == b); - REQUIRE(a->refCount == 2); - REQUIRE(a != c); - REQUIRE(c->refCount == 1); - - quantum__rt__string_update_reference_count(a, -1); - REQUIRE(b->str.compare("abc") == 0); - - quantum__rt__string_update_reference_count(b, -1); - quantum__rt__string_update_reference_count(c, -1); - - REQUIRE(AllocatedStrings().empty()); -} - -TEST_CASE("Strings: concatenate", "[qir_support]") -{ - QirContextScope qirctx(nullptr); - - QirString* a = quantum__rt__string_create("abc"); - QirString* b = quantum__rt__string_create("xyz"); - QirString* abExpected = quantum__rt__string_create("abcxyz"); - - QirString* ab = quantum__rt__string_concatenate(a, b); - REQUIRE(ab == abExpected); - - QirString* aa = quantum__rt__string_concatenate(a, a); - REQUIRE(aa->str.compare("abcabc") == 0); - - quantum__rt__string_update_reference_count(a, -1); - quantum__rt__string_update_reference_count(b, -1); - quantum__rt__string_update_reference_count(abExpected, -1); - quantum__rt__string_update_reference_count(ab, -1); - quantum__rt__string_update_reference_count(aa, -1); - - REQUIRE(AllocatedStrings().empty()); -} - -TEST_CASE("Strings: conversions from built-in types", "[qir_support]") -{ - QirContextScope qirctx(nullptr); - - std::vector strings; - - strings.push_back(quantum__rt__int_to_string(0)); - REQUIRE(strings.back()->str == std::string("0")); - - strings.push_back(quantum__rt__int_to_string(42)); - REQUIRE(strings.back()->str == std::string("42")); - - strings.push_back(quantum__rt__int_to_string(-42)); - REQUIRE(strings.back()->str == std::string("-42")); - - strings.push_back(quantum__rt__double_to_string(4.2)); - REQUIRE(strings.back()->str == std::string("4.20000000000000018")); // platform dependent? - - strings.push_back(quantum__rt__double_to_string(42.0)); - REQUIRE(strings.back()->str == std::string("42.0")); - - strings.push_back(quantum__rt__double_to_string(1e-9)); - REQUIRE(strings.back()->str == std::string("0.000000001")); - - strings.push_back(quantum__rt__double_to_string(0.0)); - REQUIRE(strings.back()->str == std::string("0.0")); - - strings.push_back(quantum__rt__double_to_string(-42.0)); - REQUIRE(strings.back()->str == std::string("-42.0")); - - strings.push_back(quantum__rt__double_to_string(-0.0)); - REQUIRE(strings.back()->str == std::string("-0.0")); - - strings.push_back(quantum__rt__bool_to_string(false)); - REQUIRE(strings.back()->str == std::string("false")); - - strings.push_back(quantum__rt__bool_to_string(true)); - REQUIRE(strings.back()->str == std::string("true")); - - // strings, created by conversions are reused for each type - strings.push_back(quantum__rt__int_to_string(0)); - REQUIRE(std::count(strings.begin(), strings.end(), strings.back()) == 2); - - strings.push_back(quantum__rt__double_to_string(42.0)); - REQUIRE(std::count(strings.begin(), strings.end(), strings.back()) == 2); - - strings.push_back(quantum__rt__bool_to_string(1)); - REQUIRE(std::count(strings.begin(), strings.end(), strings.back()) == 2); - - for (QirString* qstr : strings) - { - quantum__rt__string_update_reference_count(qstr, -1); - } - - REQUIRE(AllocatedStrings().empty()); -} - -TEST_CASE("Strings: conversions from custom qir types", "[qir_support]") -{ - QirContextScope qirctx(nullptr); - - QirString* qstr1 = quantum__rt__range_to_string({0, 1, 42}); - REQUIRE(qstr1->str == std::string("0..42")); - - QirString* qstr2 = quantum__rt__range_to_string({0, 3, 42}); - REQUIRE(qstr2->str == std::string("0..3..42")); - - quantum__rt__string_update_reference_count(qstr1, -1); - quantum__rt__string_update_reference_count(qstr2, -1); - - REQUIRE(AllocatedStrings().empty()); -} - -struct QubitTestQAPI : public SimulatorStub -{ - int lastId = -1; - const int maxQubits; - BitStates allocated; - - static int GetQubitId(Qubit q) - { - return static_cast(reinterpret_cast(q)); - } - - QubitTestQAPI(int maxQubits) - : maxQubits(maxQubits) - { - allocated.ExtendToInclude(maxQubits); - } - Qubit AllocateQubit() override - { - assert(this->lastId < this->maxQubits); - this->lastId++; - this->allocated.SetBitAt(this->lastId); - return reinterpret_cast(this->lastId); - } - void ReleaseQubit(Qubit qubit) override - { - const int id = GetQubitId(qubit); - INFO(id); - REQUIRE(this->allocated.IsBitSetAt(id)); - this->allocated.FlipBitAt(id); - } - std::string QubitToString(Qubit qubit) override - { - const int id = GetQubitId(qubit); - return std::to_string(id); - } - Result UseZero() override - { - return reinterpret_cast(0); - } - Result UseOne() override - { - return reinterpret_cast(1); - } - - bool HaveQubitsInFlight() const - { - return this->allocated.IsAny(); - } -}; -TEST_CASE("Qubits: allocate, release, dump", "[qir_support]") -{ - std::unique_ptr qapi = std::make_unique(3); - QirContextScope qirctx(qapi.get()); - QirString* qstr = nullptr; - - Qubit q = quantum__rt__qubit_allocate(); - qstr = quantum__rt__qubit_to_string(q); - REQUIRE(qstr->str == std::string("0")); - quantum__rt__string_update_reference_count(qstr, -1); - quantum__rt__qubit_release(q); - REQUIRE(!qapi->HaveQubitsInFlight()); - - QirArray* qs = quantum__rt__qubit_allocate_array(3); - REQUIRE(qs->ownsQubits); - REQUIRE(qs->count == 3); - REQUIRE(qs->itemSizeInBytes == sizeof(void*)); - - Qubit last = *reinterpret_cast(quantum__rt__array_get_element_ptr_1d(qs, 2)); - qstr = quantum__rt__qubit_to_string(last); - REQUIRE(qstr->str == std::string("3")); - quantum__rt__string_update_reference_count(qstr, -1); - - QirArray* copy = quantum__rt__array_copy(qs, true /*force*/); - REQUIRE(!copy->ownsQubits); - - quantum__rt__qubit_release_array(qs); - REQUIRE(!qapi->HaveQubitsInFlight()); - - // both arrays now contain dangling pointers to qubits, but we still must release them - quantum__rt__array_update_reference_count(qs, -1); - quantum__rt__array_update_reference_count(copy, -1); -} - -QirTupleHeader* FlattenControlArrays(QirTupleHeader* nestedTuple, int depth); -struct ControlledCallablesTestSimulator : public SimulatorStub -{ - int lastId = -1; - Qubit AllocateQubit() override - { - return reinterpret_cast(++this->lastId); - } - void ReleaseQubit(Qubit qubit) override {} - Result UseZero() override - { - return reinterpret_cast(0); - } - Result UseOne() override - { - return reinterpret_cast(1); - } -}; -TEST_CASE("Unpacking input tuples of nested callables (case2)", "[qir_support]") -{ - std::unique_ptr qapi = std::make_unique(); - QirContextScope qirctx(qapi.get()); - - Qubit target = quantum__rt__qubit_allocate(); - QirArray* controlsInner = quantum__rt__qubit_allocate_array(3); - QirArray* controlsOuter = quantum__rt__qubit_allocate_array(2); - - PTuple inner = quantum__rt__tuple_create(sizeof(/*QirArrray*/ void*) + sizeof(/*Qubit*/ void*)); - TupleWithControls* innerWithControls = TupleWithControls::FromTuple(inner); - innerWithControls->controls = controlsInner; - *reinterpret_cast(innerWithControls->AsTuple() + sizeof(/*QirArrray*/ void*)) = target; - - PTuple outer = quantum__rt__tuple_create(sizeof(/*QirArrray*/ void*) + sizeof(/*QirTupleHeader*/ void*)); - TupleWithControls* outerWithControls = TupleWithControls::FromTuple(outer); - outerWithControls->controls = controlsOuter; - outerWithControls->innerTuple = innerWithControls; - - QirTupleHeader* unpacked = FlattenControlArrays(outerWithControls->GetHeader(), 2 /*depth*/); - QirArray* combined = *(reinterpret_cast(unpacked->AsTuple())); - REQUIRE(5 == combined->count); - REQUIRE(!combined->ownsQubits); - REQUIRE(target == *reinterpret_cast(unpacked->AsTuple() + sizeof(/*QirArrray*/ void*))); - - unpacked->Release(); - quantum__rt__array_update_reference_count(combined, -1); - quantum__rt__tuple_update_reference_count(outer, -1); - quantum__rt__tuple_update_reference_count(inner, -1); - - // release the original resources - quantum__rt__qubit_release_array(controlsOuter); - quantum__rt__array_update_reference_count(controlsOuter, -1); - quantum__rt__qubit_release_array(controlsInner); - quantum__rt__array_update_reference_count(controlsInner, -1); - quantum__rt__qubit_release(target); -} - -TEST_CASE("Unpacking input tuples of nested callables (case1)", "[qir_support]") -{ - std::unique_ptr qapi = std::make_unique(); - QirContextScope qirctx(qapi.get()); - - Qubit target = quantum__rt__qubit_allocate(); - QirArray* controlsInner = quantum__rt__qubit_allocate_array(3); - QirArray* controlsOuter = quantum__rt__qubit_allocate_array(2); - - PTuple args = quantum__rt__tuple_create(+sizeof(/*Qubit*/ void*) + sizeof(int)); - *reinterpret_cast(args) = target; - *reinterpret_cast(args + sizeof(/*Qubit*/ void*)) = 42; - - PTuple inner = quantum__rt__tuple_create(sizeof(/*QirArrray*/ void*) + sizeof(/*Tuple*/ void*)); - TupleWithControls* innerWithControls = TupleWithControls::FromTuple(inner); - innerWithControls->controls = controlsInner; - *reinterpret_cast(innerWithControls->AsTuple() + sizeof(/*QirArrray*/ void*)) = args; - - PTuple outer = quantum__rt__tuple_create(sizeof(/*QirArrray*/ void*) + sizeof(/*QirTupleHeader*/ void*)); - TupleWithControls* outerWithControls = TupleWithControls::FromTuple(outer); - outerWithControls->controls = controlsOuter; - outerWithControls->innerTuple = innerWithControls; - - QirTupleHeader* unpacked = FlattenControlArrays(outerWithControls->GetHeader(), 2 /*depth*/); - QirArray* combined = *(reinterpret_cast(unpacked->AsTuple())); - REQUIRE(5 == combined->count); - REQUIRE(!combined->ownsQubits); - - QirTupleHeader* unpackedArgs = - QirTupleHeader::GetHeader(*reinterpret_cast(unpacked->AsTuple() + sizeof(/*QirArrray*/ void*))); - REQUIRE(target == *reinterpret_cast(unpackedArgs->AsTuple())); - REQUIRE(42 == *reinterpret_cast(unpackedArgs->AsTuple() + sizeof(/*Qubit*/ void*))); - - unpacked->Release(); - quantum__rt__array_update_reference_count(combined, -1); - quantum__rt__tuple_update_reference_count(outer, -1); - quantum__rt__tuple_update_reference_count(inner, -1); - quantum__rt__tuple_update_reference_count(args, -1); - - // release the original resources - quantum__rt__qubit_release_array(controlsOuter); - quantum__rt__array_update_reference_count(controlsOuter, -1); - quantum__rt__qubit_release_array(controlsInner); - quantum__rt__array_update_reference_count(controlsInner, -1); - quantum__rt__qubit_release(target); -} - -TEST_CASE("Allocation tracking for arrays", "[qir_support]") -{ - InitializeQirContext(nullptr /*don't need a simulator*/, true /*track allocations*/); - - QirArray* bounce = quantum__rt__array_create_1d(1, 1); - quantum__rt__array_update_reference_count(bounce, -1); - CHECK_THROWS(quantum__rt__array_update_reference_count(bounce, 1)); - - QirArray* releaseTwice = quantum__rt__array_create_1d(1, 1); - quantum__rt__array_update_reference_count(releaseTwice, -1); - CHECK_THROWS(quantum__rt__array_update_reference_count(releaseTwice, -1)); - - QirArray* maybeLeaked = quantum__rt__array_create_1d(1, 1); - CHECK_THROWS(ReleaseQirContext()); - - quantum__rt__array_update_reference_count(maybeLeaked, -1); - CHECK_NOTHROW(ReleaseQirContext()); -} - -TEST_CASE("Allocation tracking for tuples", "[qir_support]") -{ - InitializeQirContext(nullptr /*don't need a simulator*/, true /*track allocations*/); - - PTuple bounce = quantum__rt__tuple_create(1); - quantum__rt__tuple_update_reference_count(bounce, -1); - CHECK_THROWS(quantum__rt__tuple_update_reference_count(bounce, 1)); - - PTuple releaseTwice = quantum__rt__tuple_create(1); - quantum__rt__tuple_update_reference_count(releaseTwice, -1); - CHECK_THROWS(quantum__rt__tuple_update_reference_count(releaseTwice, -1)); - - PTuple maybeLeaked = quantum__rt__tuple_create(1); - CHECK_THROWS(ReleaseQirContext()); - - quantum__rt__tuple_update_reference_count(maybeLeaked, -1); - CHECK_NOTHROW(ReleaseQirContext()); -} - -static void NoopCallableEntry(PTuple, PTuple, PTuple) {} -TEST_CASE("Allocation tracking for callables", "[qir_support]") -{ - t_CallableEntry entries[4] = {NoopCallableEntry, nullptr, nullptr, nullptr}; - - InitializeQirContext(nullptr /*don't need a simulator*/, true /*track allocations*/); - - QirCallable* bounce = - quantum__rt__callable_create(entries, nullptr /*capture callbacks*/, nullptr /*capture tuple*/); - quantum__rt__callable_update_reference_count(bounce, -1); - CHECK_THROWS(quantum__rt__callable_update_reference_count(bounce, 1)); - - QirCallable* releaseTwice = - quantum__rt__callable_create(entries, nullptr /*capture callbacks*/, nullptr /*capture tuple*/); - quantum__rt__callable_update_reference_count(releaseTwice, -1); - CHECK_THROWS(quantum__rt__callable_update_reference_count(releaseTwice, -1)); - - QirCallable* maybeLeaked = - quantum__rt__callable_create(entries, nullptr /*capture callbacks*/, nullptr /*capture tuple*/); - CHECK_THROWS(ReleaseQirContext()); - - quantum__rt__callable_update_reference_count(maybeLeaked, -1); - CHECK_NOTHROW(ReleaseQirContext()); -} - -TEST_CASE("Callables: copy elision", "[qir_support]") -{ - QirContextScope qirctx(nullptr, true); - t_CallableEntry entries[4] = {NoopCallableEntry, nullptr, nullptr, nullptr}; - - QirCallable* original = - quantum__rt__callable_create(entries, nullptr /*capture callbacks*/, nullptr /*capture tuple*/); - - QirCallable* self = quantum__rt__callable_copy(original, false); - CHECK(self == original); - - QirCallable* other1 = quantum__rt__callable_copy(original, true); - CHECK(other1 != original); - - quantum__rt__callable_update_alias_count(original, 1); - QirCallable* other2 = quantum__rt__callable_copy(original, false); - CHECK(other2 != original); - quantum__rt__callable_update_alias_count(original, -1); - - quantum__rt__callable_update_reference_count(original, -1); - quantum__rt__callable_update_reference_count(self, -1); - quantum__rt__callable_update_reference_count(other1, -1); - quantum__rt__callable_update_reference_count(other2, -1); -} - -TEST_CASE("Tuples: copy elision", "[qir_support]") -{ - PTuple original = quantum__rt__tuple_create(1 /*size in bytes*/); - - PTuple self = quantum__rt__tuple_copy(original, false); - CHECK(self == original); - - PTuple other1 = quantum__rt__tuple_copy(original, true); - CHECK(other1 != original); - - quantum__rt__tuple_update_alias_count(original, 1); - PTuple other2 = quantum__rt__tuple_copy(original, false); - CHECK(other2 != original); - quantum__rt__tuple_update_alias_count(original, -1); - - quantum__rt__tuple_update_reference_count(original, -1); - quantum__rt__tuple_update_reference_count(self, -1); - quantum__rt__tuple_update_reference_count(other1, -1); - quantum__rt__tuple_update_reference_count(other2, -1); -} - -// Adjoints for R and Exp are implemented by qis, so let's check they at least do the angle invertion in adjoints. -struct AdjointsTestSimulator : public SimulatorStub -{ - int lastId = -1; - double rotationAngle = 0.0; - double exponentAngle = 0.0; - - Qubit AllocateQubit() override - { - return reinterpret_cast(++this->lastId); - } - void ReleaseQubit(Qubit qubit) override {} - Result UseZero() override - { - return reinterpret_cast(0); - } - Result UseOne() override - { - return reinterpret_cast(1); - } - - void R(PauliId, Qubit, double theta) override - { - this->rotationAngle += theta; - } - void Exp(long count, PauliId* paulis, Qubit*, double theta) override - { - this->exponentAngle += theta; - - // check that paulis were unpacked correctly (this assumes that the tests always invoke with the same axes) - REQUIRE(count == 2); - CHECK(paulis[0] == PauliId_Z); - CHECK(paulis[1] == PauliId_Y); - } - void ControlledR(long, Qubit*, PauliId, Qubit, double theta) override - { - this->rotationAngle += theta; - } - void ControlledExp(long, Qubit*, long count, PauliId* paulis, Qubit*, double theta) override - { - this->exponentAngle += theta; - - // check that paulis were unpacked correctly (this assumes that the tests always invoke with the same axes) - REQUIRE(count == 2); - CHECK(paulis[0] == PauliId_Z); - CHECK(paulis[1] == PauliId_Y); - } -}; -TEST_CASE("Adjoints of R should use inverse of the angle", "[qir_support]") -{ - std::unique_ptr qapi = std::make_unique(); - QirContextScope qirctx(qapi.get()); - - const double angle = 0.42; - - Qubit target = quantum__rt__qubit_allocate(); - QirArray* ctrls = quantum__rt__qubit_allocate_array(2); - - quantum__qis__r__body(PauliId_Y, angle, target); - quantum__qis__r__adj(PauliId_Y, angle, target); - quantum__qis__r__ctl(ctrls, PauliId_X, angle, target); - quantum__qis__r__ctladj(ctrls, PauliId_X, angle, target); - - quantum__rt__qubit_release_array(ctrls); - quantum__rt__array_update_reference_count(ctrls, -1); - quantum__rt__qubit_release(target); - - REQUIRE(qapi->rotationAngle == Approx(0).epsilon(0.0001)); -} - -TEST_CASE("Adjoints of Exp should use inverse of the angle", "[qir_support]") -{ - std::unique_ptr qapi = std::make_unique(); - QirContextScope qirctx(qapi.get()); - - const double angle = 0.42; - - QirArray* targets = quantum__rt__qubit_allocate_array(2); - QirArray* ctrls = quantum__rt__qubit_allocate_array(2); - QirArray* axes = quantum__rt__array_create_1d(1 /*element size*/, 2 /*count*/); - axes->buffer[0] = 2; - axes->buffer[1] = 3; - - quantum__qis__exp__body(axes, angle, targets); - quantum__qis__exp__adj(axes, angle, targets); - quantum__qis__exp__ctl(ctrls, axes, angle, targets); - quantum__qis__exp__ctladj(ctrls, axes, angle, targets); - - quantum__rt__qubit_release_array(ctrls); - quantum__rt__array_update_reference_count(ctrls, -1); - quantum__rt__qubit_release_array(targets); - quantum__rt__array_update_reference_count(targets, -1); - - REQUIRE(qapi->exponentAngle == Approx(0).epsilon(0.0001)); -} +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "catch.hpp" + +#include +#include // for memcpy +#include +#include +#include + +#include "QirTypes.hpp" +#include "qsharp__foundation__qis.hpp" +#include "qsharp__core__qis.hpp" +#include "QirRuntime.hpp" + +#include "QirContext.hpp" +#include "SimulatorStub.hpp" + +using namespace Microsoft::Quantum; + +struct ResultsReferenceCountingTestQAPI : public SimulatorStub +{ + int lastId = -1; + const int maxResults; + std::vector allocated; + + static int GetResultId(Result r) + { + return static_cast(reinterpret_cast(r)); + } + + ResultsReferenceCountingTestQAPI(int maxResults) + : maxResults(maxResults), + allocated(maxResults, false) + { + } + + Result Measure(long, PauliId[], long, Qubit[]) override + { + assert(this->lastId < this->maxResults); + this->lastId++; + this->allocated.at(this->lastId) = true;; + return reinterpret_cast(this->lastId); + } + Result UseZero() override + { + return reinterpret_cast(0); + } + Result UseOne() override + { + return reinterpret_cast(1); + } + void ReleaseResult(Result result) override + { + const int id = GetResultId(result); + INFO(id); + REQUIRE(this->allocated.at(id)); + this->allocated.at(id).flip(); + } + bool AreEqualResults(Result r1, Result r2) override + { + return (r1 == r2); + } + + bool HaveResultsInFlight() const + { + for (const auto& b : this->allocated) + { + if (b) + { + return true; + } + } + return false; + } +}; +TEST_CASE("Results: comparison and reference counting", "[qir_support]") +{ + std::unique_ptr qapi = std::make_unique(3); + QirContextScope qirctx(qapi.get()); + + Result r1 = qapi->Measure(0, nullptr, 0, nullptr); // we don't need real qubits for this test + Result r2 = qapi->Measure(0, nullptr, 0, nullptr); + REQUIRE(quantum__rt__result_equal(r1, r1)); + REQUIRE(!quantum__rt__result_equal(r1, r2)); + + // release result that has never been shared, the test QAPI will verify double release + quantum__rt__result_update_reference_count(r2, -1); + + // share a result a few times + quantum__rt__result_update_reference_count(r1, 2); + + Result r3 = qapi->Measure(0, nullptr, 0, nullptr); + + // release shared result, the test QAPI will verify double release + quantum__rt__result_update_reference_count(r1, -3); // one release for shared and for the original allocation + + REQUIRE(qapi->HaveResultsInFlight()); // r3 should be still alive + quantum__rt__result_update_reference_count(r3, -1); + + REQUIRE(!qapi->HaveResultsInFlight()); // no leaks +} + +TEST_CASE("Arrays: one dimensional", "[qir_support]") +{ + QirContextScope qirctx(nullptr); + QirArray* a = quantum__rt__array_create_1d(sizeof(char), 5); + + memcpy(a->buffer, "Hello", 5); + REQUIRE(*quantum__rt__array_get_element_ptr_1d(a, 4) == 'o'); + REQUIRE(quantum__rt__array_get_dim(a) == 1); + REQUIRE(quantum__rt__array_get_size(a, 0) == 5); + + QirArray* b = new QirArray(1, sizeof(char)); + *quantum__rt__array_get_element_ptr_1d(b, 0) = '!'; + + QirArray* ab = quantum__rt__array_concatenate(a, b); + REQUIRE(quantum__rt__array_get_size(ab, 0) == 6); + REQUIRE(*quantum__rt__array_get_element_ptr_1d(ab, 4) == 'o'); + REQUIRE(*quantum__rt__array_get_element_ptr_1d(ab, 5) == '!'); + + quantum__rt__array_update_reference_count(a, -1); + quantum__rt__array_update_reference_count(b, -1); + quantum__rt__array_update_reference_count(ab, -1); +} + +TEST_CASE("Arrays: multiple dimensions", "[qir_support]") +{ + QirContextScope qirctx(nullptr); + + const int64_t count = 5 * 3 * 4; // 60 + QirArray* a = quantum__rt__array_create(sizeof(int), 3, (int64_t)5, (int64_t)3, (int64_t)4); + REQUIRE(quantum__rt__array_get_dim(a) == 3); + REQUIRE(quantum__rt__array_get_size(a, 0) == 5); + REQUIRE(quantum__rt__array_get_size(a, 1) == 3); + REQUIRE(quantum__rt__array_get_size(a, 2) == 4); + + std::vector data(count, 0); + for (int i = 0; i < count; i++) + { + data[i] = i; + } + // 000 001 002 003 | 010 011 012 013 | 020 021 022 023 -- [0 - 11] + // 100 101 102 103 | 110 111 112 113 | 120 121 122 123 -- [12 - 23] + // ... [24 - 35] + // ... [36 - 47] + // 400 401 402 403 | 410 411 412 413 | 420 421 422 423 -- [48 - 59] + memcpy(a->buffer, reinterpret_cast(data.data()), count * sizeof(int)); + REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(a, 0, 0, 1))) == 1); + REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(a, 0, 1, 0))) == 4); + REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(a, 1, 0, 0))) == 12); + REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(a, 4, 2, 3))) == 59); + + QirArray* b = quantum__rt__array_copy(a, true /*force*/); + *(reinterpret_cast(quantum__rt__array_get_element_ptr(b, 1, 2, 3))) = 42; + REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(a, 1, 2, 3))) == 23); + + quantum__rt__array_update_reference_count(a, -1); + quantum__rt__array_update_reference_count(b, -1); +} + +TEST_CASE("Arrays: copy elision", "[qir_support]") +{ + QirContextScope qirctx(nullptr); + + QirArray* copy = quantum__rt__array_copy(nullptr, true /*force*/); + CHECK(copy == nullptr); + + QirArray* a = quantum__rt__array_create_1d(sizeof(char), 5); + // the `a` array contains garbage but for this test we don't care + + // no aliases for the array, copy should be elided unless enforced + copy = quantum__rt__array_copy(a, false /*force*/); + CHECK(a == copy); + quantum__rt__array_update_reference_count(copy, -1); + + // single alias for the array, but copy enforced + copy = quantum__rt__array_copy(a, true /*force*/); + CHECK(a != copy); + quantum__rt__array_update_reference_count(copy, -1); + + // existing aliases for the array -- cannot elide copy + quantum__rt__array_update_alias_count(a, 1); + copy = quantum__rt__array_copy(a, false /*force*/); + CHECK(a != copy); + quantum__rt__array_update_reference_count(copy, -1); + + quantum__rt__array_update_reference_count(a, -1); +} + +TEST_CASE("Arrays: empty", "[qir_support]") +{ + QirContextScope qirctx(nullptr); + + QirArray* b = quantum__rt__array_create(sizeof(int), 3, (int64_t)4, (int64_t)0, (int64_t)3); + REQUIRE(quantum__rt__array_get_dim(b) == 3); + REQUIRE(quantum__rt__array_get_size(b, 0) == 4); + REQUIRE(quantum__rt__array_get_size(b, 1) == 0); + REQUIRE(quantum__rt__array_get_size(b, 2) == 3); + REQUIRE(b->buffer == nullptr); + quantum__rt__array_update_reference_count(b, -1); + + QirArray* a = quantum__rt__array_create_1d(sizeof(char), 0); + REQUIRE(quantum__rt__array_get_dim(a) == 1); + REQUIRE(quantum__rt__array_get_size(a, 0) == 0); + REQUIRE(a->buffer == nullptr); + + QirArray* a1 = quantum__rt__array_copy(a, true /*force*/); + REQUIRE(quantum__rt__array_get_dim(a1) == 1); + REQUIRE(quantum__rt__array_get_size(a1, 0) == 0); + REQUIRE(a1->buffer == nullptr); + quantum__rt__array_update_reference_count(a1, -1); + + QirArray* c = quantum__rt__array_create_1d(sizeof(char), 5); + memcpy(c->buffer, "hello", 5); + QirArray* ac = quantum__rt__array_concatenate(a, c); + REQUIRE(quantum__rt__array_get_size(ac, 0) == 5); + QirArray* ca = quantum__rt__array_concatenate(c, a); + REQUIRE(quantum__rt__array_get_size(ca, 0) == 5); + + quantum__rt__array_update_reference_count(a, -1); + quantum__rt__array_update_reference_count(ac, -1); + quantum__rt__array_update_reference_count(ca, -1); +} + +TEST_CASE("Arrays: check the slice range", "[qir_support]") +{ + QirContextScope qirctx(nullptr); + + const int64_t dim0 = 5; + const int64_t dim1 = 6; + QirArray* a = quantum__rt__array_create(sizeof(int), 2, dim0, dim1); + QirArray* slice = nullptr; + + // invalid range + CHECK_THROWS(quantum__rt__array_slice(a, 0, {0, 0, 0})); + + // violated bounds + CHECK_THROWS(quantum__rt__array_slice(a, 0, {dim0, 1, dim0})); + CHECK_THROWS(quantum__rt__array_slice(a, 1, {0, 1, dim1})); + CHECK_THROWS(quantum__rt__array_slice(a, 0, {-1, 1, dim0 - 1})); + + CHECK_THROWS(quantum__rt__array_slice(a, 0, {dim0, -1, dim0})); + CHECK_THROWS(quantum__rt__array_slice(a, 1, {dim1, -1, 0})); + CHECK_THROWS(quantum__rt__array_slice(a, 0, {dim0 - 1, -1, -1})); + + CHECK_THROWS(quantum__rt__array_slice(a, 0, {dim0, 3, dim0})); + CHECK_THROWS(quantum__rt__array_slice(a, 1, {0, 3, dim1 + 2})); + CHECK_THROWS(quantum__rt__array_slice(a, 0, {-1, 3, dim0 - 1})); + + CHECK_THROWS(quantum__rt__array_slice(a, 0, {dim0, -3, dim0})); + CHECK_THROWS(quantum__rt__array_slice(a, 1, {dim1, -3, 0})); + CHECK_THROWS(quantum__rt__array_slice(a, 0, {dim0 - 1, -3, -3})); + + // empty range should produce empty array + slice = quantum__rt__array_slice(a, 0, {dim0 - 1, 1, 0}); + REQUIRE(quantum__rt__array_get_size(slice, 0) == 0); + REQUIRE(quantum__rt__array_get_size(slice, 1) == dim1); + quantum__rt__array_update_reference_count(slice, -1); + + slice = quantum__rt__array_slice(a, 1, {0, -1, dim0 - 1}); + REQUIRE(quantum__rt__array_get_size(slice, 0) == dim0); + REQUIRE(quantum__rt__array_get_size(slice, 1) == 0); + quantum__rt__array_update_reference_count(slice, -1); + + quantum__rt__array_update_reference_count(a, -1); +} + +TEST_CASE("Arrays: slice of 1D array", "[qir_support]") +{ + QirContextScope qirctx(nullptr); + + const int64_t dim = 5; + QirArray* a = quantum__rt__array_create_1d(sizeof(char), dim); + memcpy(a->buffer, "01234", 5); + QirArray* slice = nullptr; + + // even if slice results in a single value, it's still an array + slice = quantum__rt__array_slice(a, 0, {1, 2 * dim, dim}); + REQUIRE(quantum__rt__array_get_size(slice, 0) == 1); + REQUIRE(*quantum__rt__array_get_element_ptr_1d(slice, 0) == '1'); + quantum__rt__array_update_reference_count(slice, -1); + + // if the range covers the whole array, it's effectively a copy + slice = quantum__rt__array_slice(a, 0, {0, 1, dim - 1}); + REQUIRE(quantum__rt__array_get_size(slice, 0) == dim); + REQUIRE(*quantum__rt__array_get_element_ptr_1d(slice, 0) == '0'); + REQUIRE(*quantum__rt__array_get_element_ptr(slice, 4) == '4'); + quantum__rt__array_update_reference_count(slice, -1); + + // disconnected slice (also check that the end of range can be above bounds as long as the generated sequence is + // within them) + slice = quantum__rt__array_slice(a, 0, {0, 4, dim + 1}); + REQUIRE(quantum__rt__array_get_size(slice, 0) == 2); + REQUIRE(*quantum__rt__array_get_element_ptr_1d(slice, 0) == '0'); + REQUIRE(*quantum__rt__array_get_element_ptr_1d(slice, 1) == '4'); + quantum__rt__array_update_reference_count(slice, -1); + + quantum__rt__array_update_reference_count(a, -1); +} + +TEST_CASE("Arrays: reversed slice of 1D array", "[qir_support]") +{ + QirContextScope qirctx(nullptr); + const int64_t dim = 5; + QirArray* a = quantum__rt__array_create_1d(sizeof(char), dim); + memcpy(a->buffer, "01234", 5); + QirArray* slice = nullptr; + + // even if slice results in a single value, it's still an array + slice = quantum__rt__array_slice(a, 0, {1, -dim, 0}); + REQUIRE(quantum__rt__array_get_size(slice, 0) == 1); + REQUIRE(*quantum__rt__array_get_element_ptr_1d(slice, 0) == '1'); + quantum__rt__array_update_reference_count(slice, -1); + + // reversed slices are alwayes disconnected + slice = quantum__rt__array_slice(a, 0, {dim - 1, -2, 0}); + REQUIRE(quantum__rt__array_get_size(slice, 0) == 3); + REQUIRE(*quantum__rt__array_get_element_ptr_1d(slice, 0) == '4'); + REQUIRE(*quantum__rt__array_get_element_ptr_1d(slice, 1) == '2'); + REQUIRE(*quantum__rt__array_get_element_ptr_1d(slice, 2) == '0'); + quantum__rt__array_update_reference_count(slice, -1); + + quantum__rt__array_update_reference_count(a, -1); +} + +TEST_CASE("Arrays: slice of 3D array", "[qir_support]") +{ + QirContextScope qirctx(nullptr); + + const int32_t dims = 3; + const int64_t dim0 = 5; + const int64_t dim1 = 3; + const int64_t dim2 = 4; + + QirArray* a = quantum__rt__array_create(sizeof(int), dims, dim0, dim1, dim2); + QirArray* slice = nullptr; + + const int64_t count = dim0 * dim1 * dim2; // 60 + std::vector data(count, 0); + for (int i = 0; i < count; i++) + { + data[i] = i; + } + // indexes -- values + // 000 001 002 003 | 010 011 012 013 | 020 021 022 023 -- [0 - 11] + // 100 101 102 103 | 110 111 112 113 | 120 121 122 123 -- [12 - 23] + // ... [24 - 35] + // ... [36 - 47] + // 400 401 402 403 | 410 411 412 413 | 420 421 422 423 -- [48 - 59] + memcpy(a->buffer, reinterpret_cast(data.data()), count * sizeof(int)); + REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(a, 1, 0, 0))) == 12); + REQUIRE( + *(reinterpret_cast(quantum__rt__array_get_element_ptr(a, dim0 - 1, dim1 - 1, dim2 - 1))) == count - 1); + + // if the range covers the whole dimension, it's effectively a copy + slice = quantum__rt__array_slice(a, 1, {0, 1, dim1 - 1}); + REQUIRE(quantum__rt__array_get_dim(slice) == dims); + REQUIRE(quantum__rt__array_get_size(slice, 0) == dim0); + REQUIRE(quantum__rt__array_get_size(slice, 1) == dim1); + REQUIRE(quantum__rt__array_get_size(slice, 2) == dim2); + REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 1, 0, 0))) == 12); + REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 4, 2, 3))) == 59); + quantum__rt__array_update_reference_count(slice, -1); + + // if the range consists of a single point, the slice still has the same dimensions + slice = quantum__rt__array_slice(a, 1, {1, 2 * dim1, dim1}); // items with second index = 1 + REQUIRE(quantum__rt__array_get_dim(slice) == dims); + REQUIRE(quantum__rt__array_get_size(slice, 0) == dim0); + REQUIRE(quantum__rt__array_get_size(slice, 1) == 1); + REQUIRE(quantum__rt__array_get_size(slice, 2) == dim2); + REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 0, 0, 0))) == 4); + REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 4, 0, 3))) == 55); + quantum__rt__array_update_reference_count(slice, -1); + + // slice on 0 dimension + slice = quantum__rt__array_slice(a, 0, {1, 1, 3}); // items with first index = 1, 2 or 3 + REQUIRE(quantum__rt__array_get_dim(slice) == dims); + REQUIRE(quantum__rt__array_get_size(slice, 0) == 3); + REQUIRE(quantum__rt__array_get_size(slice, 1) == dim1); + REQUIRE(quantum__rt__array_get_size(slice, 2) == dim2); + REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 0, 0, 0))) == 12); + REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 2, 2, 3))) == 47); + quantum__rt__array_update_reference_count(slice, -1); + + // slice on last dimension, expected result: + // indexes -- values + // 000 001 | 010 011 | 020 021 -- [ 1 2 | 5 6 | 9 10] + // 100 101 | 110 111 | 120 121 -- [13 14 | 17 18 | 21 22] + // ... [25 ... ] + // ... [37 ... ] + // 400 401 | 410 411 | 420 421 -- [49 50 | 53 54 | 57 58] + slice = quantum__rt__array_slice(a, 2, {1, 1, 2}); // items with last index = 1 or 2 + REQUIRE(quantum__rt__array_get_dim(slice) == dims); + REQUIRE(quantum__rt__array_get_size(slice, 0) == dim0); + REQUIRE(quantum__rt__array_get_size(slice, 1) == dim1); + REQUIRE(quantum__rt__array_get_size(slice, 2) == 2); + REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 0, 0, 0))) == 1); + REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 0, 2, 1))) == 10); + REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 1, 1, 1))) == 18); + REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 4, 2, 1))) == 58); + quantum__rt__array_update_reference_count(slice, -1); + + // slice on sparse range in 0 dimension (also check that the end of range can be above bounds as long as the + // generated sequence is within them) + slice = quantum__rt__array_slice(a, 0, {0, 3, dim0}); // items with first index = 0 or 3 + REQUIRE(quantum__rt__array_get_dim(slice) == dims); + REQUIRE(quantum__rt__array_get_size(slice, 0) == 2); + REQUIRE(quantum__rt__array_get_size(slice, 1) == dim1); + REQUIRE(quantum__rt__array_get_size(slice, 2) == dim2); + REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 0, 0, 0))) == 0); + REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 1, 2, 3))) == 47); + quantum__rt__array_update_reference_count(slice, -1); + + // slice on sparse range in the middle dimension + slice = quantum__rt__array_slice(a, 1, {0, 2, 2}); // items with second index = 0 or 2 + REQUIRE(quantum__rt__array_get_dim(slice) == dims); + REQUIRE(quantum__rt__array_get_size(slice, 0) == dim0); + REQUIRE(quantum__rt__array_get_size(slice, 1) == 2); + REQUIRE(quantum__rt__array_get_size(slice, 2) == dim2); + REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 0, 0, 0))) == 0); + REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 4, 1, 3))) == 59); + quantum__rt__array_update_reference_count(slice, -1); + + // slice on sparse range in the last dimension + // indexes -- values + // 000 001 | 010 011 | 020 021 -- [01 03 | 05 07 | 09 11] + // 100 101 | 110 111 | 120 121 -- [13 15 | 17 19 | 21 23] + // ... -- [25 ... ] + // ... -- [37 ... ] + // 400 401 | 410 411 | 420 421 -- [49 51 | 53 55 | 57 59] + slice = quantum__rt__array_slice(a, 2, {1, 2, 3}); // items with last index = 1 or 3 (all odd numbers) + REQUIRE(quantum__rt__array_get_dim(slice) == dims); + REQUIRE(quantum__rt__array_get_size(slice, 0) == dim0); + REQUIRE(quantum__rt__array_get_size(slice, 1) == dim1); + REQUIRE(quantum__rt__array_get_size(slice, 2) == 2); + REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 0, 0, 0))) == 1); + REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 0, 2, 1))) == 11); + REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 1, 1, 0))) == 17); + REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 4, 2, 1))) == 59); + quantum__rt__array_update_reference_count(slice, -1); + + quantum__rt__array_update_reference_count(a, -1); +} + +TEST_CASE("Arrays: reversed slice of 3D array", "[qir_support]") +{ + QirContextScope qirctx(nullptr); + + const int32_t dims = 3; + const int64_t dim0 = 5; + const int64_t dim1 = 3; + const int64_t dim2 = 4; + + QirArray* a = quantum__rt__array_create(sizeof(int), dims, dim0, dim1, dim2); + QirArray* slice = nullptr; + + const int64_t count = dim0 * dim1 * dim2; // 60 + std::vector data(count, 0); + for (int i = 0; i < count; i++) + { + data[i] = i; + } + // indexes -- values + // 000 001 002 003 | 010 011 012 013 | 020 021 022 023 -- [0 - 11] + // 100 101 102 103 | 110 111 112 113 | 120 121 122 123 -- [12 - 23] + // ... [24 - 35] + // ... [36 - 47] + // 400 401 402 403 | 410 411 412 413 | 420 421 422 423 -- [48 - 59] + memcpy(a->buffer, reinterpret_cast(data.data()), count * sizeof(int)); + REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(a, 1, 0, 0))) == 12); + REQUIRE( + *(reinterpret_cast(quantum__rt__array_get_element_ptr(a, dim0 - 1, dim1 - 1, dim2 - 1))) == count - 1); + + // if the range consists of a single point, the slice still has the same dimensions + slice = quantum__rt__array_slice(a, 1, {1, -dim1, 0}); // items with second index = 1 + REQUIRE(quantum__rt__array_get_dim(slice) == dims); + REQUIRE(quantum__rt__array_get_size(slice, 0) == dim0); + REQUIRE(quantum__rt__array_get_size(slice, 1) == 1); + REQUIRE(quantum__rt__array_get_size(slice, 2) == dim2); + REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 0, 0, 0))) == 4); + REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 4, 0, 3))) == 55); + quantum__rt__array_update_reference_count(slice, -1); + + // slice on dim0, expect the result to look like: + // indexes -- values + // 000 001 002 003 | 010 011 012 013 | 020 021 022 023 -- [36 - 47] + // 100 101 102 103 | 110 111 112 113 | 120 121 122 123 -- [24 - 35] + // 200 201 202 203 | 210 211 212 213 | 220 221 222 223 -- [12 - 23] + slice = quantum__rt__array_slice(a, 0, {dim0 - 2, -1, 1}); + REQUIRE(quantum__rt__array_get_dim(slice) == dims); + REQUIRE(quantum__rt__array_get_size(slice, 0) == 3); + REQUIRE(quantum__rt__array_get_size(slice, 1) == dim1); + REQUIRE(quantum__rt__array_get_size(slice, 2) == dim2); + REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 0, 0, 0))) == 36); + REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 2, 2, 3))) == 23); + quantum__rt__array_update_reference_count(slice, -1); + + // slice on last dimension, expect the result to look like: + // indexes -- values + // 000 001 | 010 011 | 020 021 -- [03 01 | 07 05 | 11 09] + // 100 101 | 110 111 | 120 121 -- [15 13 | 19 17 | 23 21] + // ... -- [27 ... ] + // ... -- [39 ... ] + // 400 401 | 410 411 | 420 421 -- [51 49 | 55 53 | 59 57] + slice = quantum__rt__array_slice(a, 2, {dim2 - 1, -2, 0}); // items with last index 3, 1 (all odd numbers) + REQUIRE(quantum__rt__array_get_dim(slice) == dims); + REQUIRE(quantum__rt__array_get_size(slice, 0) == dim0); + REQUIRE(quantum__rt__array_get_size(slice, 1) == dim1); + REQUIRE(quantum__rt__array_get_size(slice, 2) == 2); + REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 0, 0, 0))) == 3); + REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 0, 2, 1))) == 9); + REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 1, 1, 0))) == 19); + REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(slice, 4, 2, 1))) == 57); + quantum__rt__array_update_reference_count(slice, -1); +} + +TEST_CASE("Arrays: project of 3D array", "[qir_support]") +{ + QirContextScope qirctx(nullptr); + + const int32_t dims = 3; + const int64_t dim0 = 5; + const int64_t dim1 = 3; + const int64_t dim2 = 4; + + QirArray* a = quantum__rt__array_create(sizeof(int), dims, dim0, dim1, dim2); + QirArray* project = nullptr; + + const int64_t count = dim0 * dim1 * dim2; // 60 + std::vector data(count, 0); + for (int i = 0; i < count; i++) + { + data[i] = i; + } + // indexes -- values + // 000 001 002 003 | 010 011 012 013 | 020 021 022 023 -- [0 - 11] + // 100 101 102 103 | 110 111 112 113 | 120 121 122 123 -- [12 - 23] + // ... [24 - 35] + // ... [36 - 47] + // 400 401 402 403 | 410 411 412 413 | 420 421 422 423 -- [48 - 59] + memcpy(a->buffer, reinterpret_cast(data.data()), count * sizeof(int)); + REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(a, 1, 0, 0))) == 12); + REQUIRE( + *(reinterpret_cast(quantum__rt__array_get_element_ptr(a, dim0 - 1, dim1 - 1, dim2 - 1))) == count - 1); + + // project on 0 dimension, expected result: + // indexes -- values + // 00 01 02 03 | 10 11 12 13 | 20 21 22 23 -- [12 - 23] + project = quantum__rt__array_project(a, 0, 1); // items with first index = 1 + REQUIRE(quantum__rt__array_get_dim(project) == dims - 1); + REQUIRE(quantum__rt__array_get_size(project, 0) == dim1); + REQUIRE(quantum__rt__array_get_size(project, 1) == dim2); + REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(project, 0, 0))) == 12); + REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(project, 1, 1))) == 17); + REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(project, 2, 3))) == 23); + quantum__rt__array_update_reference_count(project, -1); + + // project on last dimension, expected result: + // indexes -- values + // 00 | 01 | 02 -- [02 06 10] + // 10 | 11 | 12 -- [14 18 22] + // ... -- [26 30 34] + // ... -- [38 42 46] + // 40 | 41 | 42 -- [50 54 58] + project = quantum__rt__array_project(a, 2, 2); // items with last index = 2 + REQUIRE(quantum__rt__array_get_dim(project) == dims - 1); + REQUIRE(quantum__rt__array_get_size(project, 0) == dim0); + REQUIRE(quantum__rt__array_get_size(project, 1) == dim1); + REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(project, 0, 0, 0))) == 2); + REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(project, 1, 1, 2))) == 18); + REQUIRE(*(reinterpret_cast(quantum__rt__array_get_element_ptr(project, 4, 2, 2))) == 58); + quantum__rt__array_update_reference_count(project, -1); + + quantum__rt__array_update_reference_count(a, -1); +} + +std::unordered_map& AllocatedStrings(); +TEST_CASE("Strings: reuse", "[qir_support]") +{ + QirContextScope qirctx(nullptr); + + QirString* a = quantum__rt__string_create("abc"); + QirString* b = quantum__rt__string_create("abc"); + QirString* c = quantum__rt__string_create("xyz"); + + REQUIRE(a == b); + REQUIRE(a->refCount == 2); + REQUIRE(a != c); + REQUIRE(c->refCount == 1); + + quantum__rt__string_update_reference_count(a, -1); + REQUIRE(b->str.compare("abc") == 0); + + quantum__rt__string_update_reference_count(b, -1); + quantum__rt__string_update_reference_count(c, -1); + + REQUIRE(AllocatedStrings().empty()); +} + +TEST_CASE("Strings: concatenate", "[qir_support]") +{ + QirContextScope qirctx(nullptr); + + QirString* a = quantum__rt__string_create("abc"); + QirString* b = quantum__rt__string_create("xyz"); + QirString* abExpected = quantum__rt__string_create("abcxyz"); + + QirString* ab = quantum__rt__string_concatenate(a, b); + REQUIRE(ab == abExpected); + + QirString* aa = quantum__rt__string_concatenate(a, a); + REQUIRE(aa->str.compare("abcabc") == 0); + + quantum__rt__string_update_reference_count(a, -1); + quantum__rt__string_update_reference_count(b, -1); + quantum__rt__string_update_reference_count(abExpected, -1); + quantum__rt__string_update_reference_count(ab, -1); + quantum__rt__string_update_reference_count(aa, -1); + + REQUIRE(AllocatedStrings().empty()); +} + +TEST_CASE("Strings: conversions from built-in types", "[qir_support]") +{ + QirContextScope qirctx(nullptr); + + std::vector strings; + + strings.push_back(quantum__rt__int_to_string(0)); + REQUIRE(strings.back()->str == std::string("0")); + + strings.push_back(quantum__rt__int_to_string(42)); + REQUIRE(strings.back()->str == std::string("42")); + + strings.push_back(quantum__rt__int_to_string(-42)); + REQUIRE(strings.back()->str == std::string("-42")); + + strings.push_back(quantum__rt__double_to_string(4.2)); + REQUIRE(strings.back()->str == std::string("4.20000000000000018")); // platform dependent? + + strings.push_back(quantum__rt__double_to_string(42.0)); + REQUIRE(strings.back()->str == std::string("42.0")); + + strings.push_back(quantum__rt__double_to_string(1e-9)); + REQUIRE(strings.back()->str == std::string("0.000000001")); + + strings.push_back(quantum__rt__double_to_string(0.0)); + REQUIRE(strings.back()->str == std::string("0.0")); + + strings.push_back(quantum__rt__double_to_string(-42.0)); + REQUIRE(strings.back()->str == std::string("-42.0")); + + strings.push_back(quantum__rt__double_to_string(-0.0)); + REQUIRE(strings.back()->str == std::string("-0.0")); + + strings.push_back(quantum__rt__bool_to_string(false)); + REQUIRE(strings.back()->str == std::string("false")); + + strings.push_back(quantum__rt__bool_to_string(true)); + REQUIRE(strings.back()->str == std::string("true")); + + // strings, created by conversions are reused for each type + strings.push_back(quantum__rt__int_to_string(0)); + REQUIRE(std::count(strings.begin(), strings.end(), strings.back()) == 2); + + strings.push_back(quantum__rt__double_to_string(42.0)); + REQUIRE(std::count(strings.begin(), strings.end(), strings.back()) == 2); + + strings.push_back(quantum__rt__bool_to_string(1)); + REQUIRE(std::count(strings.begin(), strings.end(), strings.back()) == 2); + + for (QirString* qstr : strings) + { + quantum__rt__string_update_reference_count(qstr, -1); + } + + REQUIRE(AllocatedStrings().empty()); +} + +TEST_CASE("Strings: conversions from custom qir types", "[qir_support]") +{ + QirContextScope qirctx(nullptr); + + QirString* qstr1 = quantum__rt__range_to_string({0, 1, 42}); + REQUIRE(qstr1->str == std::string("0..42")); + + QirString* qstr2 = quantum__rt__range_to_string({0, 3, 42}); + REQUIRE(qstr2->str == std::string("0..3..42")); + + quantum__rt__string_update_reference_count(qstr1, -1); + quantum__rt__string_update_reference_count(qstr2, -1); + + REQUIRE(AllocatedStrings().empty()); +} + +struct QubitTestQAPI : public SimulatorStub +{ + int lastId = -1; + const int maxQubits; + std::vector allocated; + + static int GetQubitId(Qubit q) + { + return static_cast(reinterpret_cast(q)); + } + + QubitTestQAPI(int maxQubits) + : maxQubits(maxQubits), + allocated(maxQubits, false) + { + } + + Qubit AllocateQubit() override + { + assert(this->lastId < this->maxQubits); + this->lastId++; + this->allocated.at(this->lastId) = true; + return reinterpret_cast(this->lastId); + } + void ReleaseQubit(Qubit qubit) override + { + const int id = GetQubitId(qubit); + INFO(id); + REQUIRE(this->allocated.at(id)); + this->allocated.at(id).flip(); + } + std::string QubitToString(Qubit qubit) override + { + const int id = GetQubitId(qubit); + return std::to_string(id); + } + Result UseZero() override + { + return reinterpret_cast(0); + } + Result UseOne() override + { + return reinterpret_cast(1); + } + + bool HaveQubitsInFlight() const + { + for (const auto& b : this->allocated) + { + if (b) + { + return true; + } + } + return false; + } +}; +TEST_CASE("Qubits: allocate, release, dump", "[qir_support]") +{ + std::unique_ptr qapi = std::make_unique(4); + QirContextScope qirctx(qapi.get()); + QirString* qstr = nullptr; + + Qubit q = quantum__rt__qubit_allocate(); + qstr = quantum__rt__qubit_to_string(q); + REQUIRE(qstr->str == std::string("0")); + quantum__rt__string_update_reference_count(qstr, -1); + quantum__rt__qubit_release(q); + REQUIRE(!qapi->HaveQubitsInFlight()); + + QirArray* qs = quantum__rt__qubit_allocate_array(3); + REQUIRE(qs->ownsQubits); + REQUIRE(qs->count == 3); + REQUIRE(qs->itemSizeInBytes == sizeof(void*)); + + Qubit last = *reinterpret_cast(quantum__rt__array_get_element_ptr_1d(qs, 2)); + qstr = quantum__rt__qubit_to_string(last); + REQUIRE(qstr->str == std::string("3")); + quantum__rt__string_update_reference_count(qstr, -1); + + QirArray* copy = quantum__rt__array_copy(qs, true /*force*/); + REQUIRE(!copy->ownsQubits); + + quantum__rt__qubit_release_array(qs); + REQUIRE(!qapi->HaveQubitsInFlight()); + + // both arrays now contain dangling pointers to qubits, but we still must release them + quantum__rt__array_update_reference_count(qs, -1); + quantum__rt__array_update_reference_count(copy, -1); +} + +QirTupleHeader* FlattenControlArrays(QirTupleHeader* nestedTuple, int depth); +struct ControlledCallablesTestSimulator : public SimulatorStub +{ + int lastId = -1; + Qubit AllocateQubit() override + { + return reinterpret_cast(++this->lastId); + } + void ReleaseQubit(Qubit qubit) override {} + Result UseZero() override + { + return reinterpret_cast(0); + } + Result UseOne() override + { + return reinterpret_cast(1); + } +}; +TEST_CASE("Unpacking input tuples of nested callables (case2)", "[qir_support]") +{ + std::unique_ptr qapi = std::make_unique(); + QirContextScope qirctx(qapi.get()); + + Qubit target = quantum__rt__qubit_allocate(); + QirArray* controlsInner = quantum__rt__qubit_allocate_array(3); + QirArray* controlsOuter = quantum__rt__qubit_allocate_array(2); + + PTuple inner = quantum__rt__tuple_create(sizeof(/*QirArrray*/ void*) + sizeof(/*Qubit*/ void*)); + TupleWithControls* innerWithControls = TupleWithControls::FromTuple(inner); + innerWithControls->controls = controlsInner; + *reinterpret_cast(innerWithControls->AsTuple() + sizeof(/*QirArrray*/ void*)) = target; + + PTuple outer = quantum__rt__tuple_create(sizeof(/*QirArrray*/ void*) + sizeof(/*QirTupleHeader*/ void*)); + TupleWithControls* outerWithControls = TupleWithControls::FromTuple(outer); + outerWithControls->controls = controlsOuter; + outerWithControls->innerTuple = innerWithControls; + + QirTupleHeader* unpacked = FlattenControlArrays(outerWithControls->GetHeader(), 2 /*depth*/); + QirArray* combined = *(reinterpret_cast(unpacked->AsTuple())); + REQUIRE(5 == combined->count); + REQUIRE(!combined->ownsQubits); + REQUIRE(target == *reinterpret_cast(unpacked->AsTuple() + sizeof(/*QirArrray*/ void*))); + + unpacked->Release(); + quantum__rt__array_update_reference_count(combined, -1); + quantum__rt__tuple_update_reference_count(outer, -1); + quantum__rt__tuple_update_reference_count(inner, -1); + + // release the original resources + quantum__rt__qubit_release_array(controlsOuter); + quantum__rt__array_update_reference_count(controlsOuter, -1); + quantum__rt__qubit_release_array(controlsInner); + quantum__rt__array_update_reference_count(controlsInner, -1); + quantum__rt__qubit_release(target); +} + +TEST_CASE("Unpacking input tuples of nested callables (case1)", "[qir_support]") +{ + std::unique_ptr qapi = std::make_unique(); + QirContextScope qirctx(qapi.get()); + + Qubit target = quantum__rt__qubit_allocate(); + QirArray* controlsInner = quantum__rt__qubit_allocate_array(3); + QirArray* controlsOuter = quantum__rt__qubit_allocate_array(2); + + PTuple args = quantum__rt__tuple_create(+sizeof(/*Qubit*/ void*) + sizeof(int)); + *reinterpret_cast(args) = target; + *reinterpret_cast(args + sizeof(/*Qubit*/ void*)) = 42; + + PTuple inner = quantum__rt__tuple_create(sizeof(/*QirArrray*/ void*) + sizeof(/*Tuple*/ void*)); + TupleWithControls* innerWithControls = TupleWithControls::FromTuple(inner); + innerWithControls->controls = controlsInner; + *reinterpret_cast(innerWithControls->AsTuple() + sizeof(/*QirArrray*/ void*)) = args; + + PTuple outer = quantum__rt__tuple_create(sizeof(/*QirArrray*/ void*) + sizeof(/*QirTupleHeader*/ void*)); + TupleWithControls* outerWithControls = TupleWithControls::FromTuple(outer); + outerWithControls->controls = controlsOuter; + outerWithControls->innerTuple = innerWithControls; + + QirTupleHeader* unpacked = FlattenControlArrays(outerWithControls->GetHeader(), 2 /*depth*/); + QirArray* combined = *(reinterpret_cast(unpacked->AsTuple())); + REQUIRE(5 == combined->count); + REQUIRE(!combined->ownsQubits); + + QirTupleHeader* unpackedArgs = + QirTupleHeader::GetHeader(*reinterpret_cast(unpacked->AsTuple() + sizeof(/*QirArrray*/ void*))); + REQUIRE(target == *reinterpret_cast(unpackedArgs->AsTuple())); + REQUIRE(42 == *reinterpret_cast(unpackedArgs->AsTuple() + sizeof(/*Qubit*/ void*))); + + unpacked->Release(); + quantum__rt__array_update_reference_count(combined, -1); + quantum__rt__tuple_update_reference_count(outer, -1); + quantum__rt__tuple_update_reference_count(inner, -1); + quantum__rt__tuple_update_reference_count(args, -1); + + // release the original resources + quantum__rt__qubit_release_array(controlsOuter); + quantum__rt__array_update_reference_count(controlsOuter, -1); + quantum__rt__qubit_release_array(controlsInner); + quantum__rt__array_update_reference_count(controlsInner, -1); + quantum__rt__qubit_release(target); +} + +TEST_CASE("Allocation tracking for arrays", "[qir_support]") +{ + InitializeQirContext(nullptr /*don't need a simulator*/, true /*track allocations*/); + + QirArray* bounce = quantum__rt__array_create_1d(1, 1); + quantum__rt__array_update_reference_count(bounce, -1); + CHECK_THROWS(quantum__rt__array_update_reference_count(bounce, 1)); + + QirArray* releaseTwice = quantum__rt__array_create_1d(1, 1); + quantum__rt__array_update_reference_count(releaseTwice, -1); + CHECK_THROWS(quantum__rt__array_update_reference_count(releaseTwice, -1)); + + QirArray* maybeLeaked = quantum__rt__array_create_1d(1, 1); + CHECK_THROWS(ReleaseQirContext()); + + quantum__rt__array_update_reference_count(maybeLeaked, -1); + CHECK_NOTHROW(ReleaseQirContext()); +} + +TEST_CASE("Allocation tracking for tuples", "[qir_support]") +{ + InitializeQirContext(nullptr /*don't need a simulator*/, true /*track allocations*/); + + PTuple bounce = quantum__rt__tuple_create(1); + quantum__rt__tuple_update_reference_count(bounce, -1); + CHECK_THROWS(quantum__rt__tuple_update_reference_count(bounce, 1)); + + PTuple releaseTwice = quantum__rt__tuple_create(1); + quantum__rt__tuple_update_reference_count(releaseTwice, -1); + CHECK_THROWS(quantum__rt__tuple_update_reference_count(releaseTwice, -1)); + + PTuple maybeLeaked = quantum__rt__tuple_create(1); + CHECK_THROWS(ReleaseQirContext()); + + quantum__rt__tuple_update_reference_count(maybeLeaked, -1); + CHECK_NOTHROW(ReleaseQirContext()); +} + +static void NoopCallableEntry(PTuple, PTuple, PTuple) {} +TEST_CASE("Allocation tracking for callables", "[qir_support]") +{ + t_CallableEntry entries[4] = {NoopCallableEntry, nullptr, nullptr, nullptr}; + + InitializeQirContext(nullptr /*don't need a simulator*/, true /*track allocations*/); + + QirCallable* bounce = + quantum__rt__callable_create(entries, nullptr /*capture callbacks*/, nullptr /*capture tuple*/); + quantum__rt__callable_update_reference_count(bounce, -1); + CHECK_THROWS(quantum__rt__callable_update_reference_count(bounce, 1)); + + QirCallable* releaseTwice = + quantum__rt__callable_create(entries, nullptr /*capture callbacks*/, nullptr /*capture tuple*/); + quantum__rt__callable_update_reference_count(releaseTwice, -1); + CHECK_THROWS(quantum__rt__callable_update_reference_count(releaseTwice, -1)); + + QirCallable* maybeLeaked = + quantum__rt__callable_create(entries, nullptr /*capture callbacks*/, nullptr /*capture tuple*/); + CHECK_THROWS(ReleaseQirContext()); + + quantum__rt__callable_update_reference_count(maybeLeaked, -1); + CHECK_NOTHROW(ReleaseQirContext()); +} + +TEST_CASE("Callables: copy elision", "[qir_support]") +{ + QirContextScope qirctx(nullptr, true); + t_CallableEntry entries[4] = {NoopCallableEntry, nullptr, nullptr, nullptr}; + + QirCallable* original = + quantum__rt__callable_create(entries, nullptr /*capture callbacks*/, nullptr /*capture tuple*/); + + QirCallable* self = quantum__rt__callable_copy(original, false); + CHECK(self == original); + + QirCallable* other1 = quantum__rt__callable_copy(original, true); + CHECK(other1 != original); + + quantum__rt__callable_update_alias_count(original, 1); + QirCallable* other2 = quantum__rt__callable_copy(original, false); + CHECK(other2 != original); + quantum__rt__callable_update_alias_count(original, -1); + + quantum__rt__callable_update_reference_count(original, -1); + quantum__rt__callable_update_reference_count(self, -1); + quantum__rt__callable_update_reference_count(other1, -1); + quantum__rt__callable_update_reference_count(other2, -1); +} + +TEST_CASE("Tuples: copy elision", "[qir_support]") +{ + PTuple original = quantum__rt__tuple_create(1 /*size in bytes*/); + + PTuple self = quantum__rt__tuple_copy(original, false); + CHECK(self == original); + + PTuple other1 = quantum__rt__tuple_copy(original, true); + CHECK(other1 != original); + + quantum__rt__tuple_update_alias_count(original, 1); + PTuple other2 = quantum__rt__tuple_copy(original, false); + CHECK(other2 != original); + quantum__rt__tuple_update_alias_count(original, -1); + + quantum__rt__tuple_update_reference_count(original, -1); + quantum__rt__tuple_update_reference_count(self, -1); + quantum__rt__tuple_update_reference_count(other1, -1); + quantum__rt__tuple_update_reference_count(other2, -1); +} + +// Adjoints for R and Exp are implemented by qis, so let's check they at least do the angle invertion in adjoints. +struct AdjointsTestSimulator : public SimulatorStub +{ + int lastId = -1; + double rotationAngle = 0.0; + double exponentAngle = 0.0; + + Qubit AllocateQubit() override + { + return reinterpret_cast(++this->lastId); + } + void ReleaseQubit(Qubit qubit) override {} + Result UseZero() override + { + return reinterpret_cast(0); + } + Result UseOne() override + { + return reinterpret_cast(1); + } + + void R(PauliId, Qubit, double theta) override + { + this->rotationAngle += theta; + } + void Exp(long count, PauliId* paulis, Qubit*, double theta) override + { + this->exponentAngle += theta; + + // check that paulis were unpacked correctly (this assumes that the tests always invoke with the same axes) + REQUIRE(count == 2); + CHECK(paulis[0] == PauliId_Z); + CHECK(paulis[1] == PauliId_Y); + } + void ControlledR(long, Qubit*, PauliId, Qubit, double theta) override + { + this->rotationAngle += theta; + } + void ControlledExp(long, Qubit*, long count, PauliId* paulis, Qubit*, double theta) override + { + this->exponentAngle += theta; + + // check that paulis were unpacked correctly (this assumes that the tests always invoke with the same axes) + REQUIRE(count == 2); + CHECK(paulis[0] == PauliId_Z); + CHECK(paulis[1] == PauliId_Y); + } +}; +TEST_CASE("Adjoints of R should use inverse of the angle", "[qir_support]") +{ + std::unique_ptr qapi = std::make_unique(); + QirContextScope qirctx(qapi.get()); + + const double angle = 0.42; + + Qubit target = quantum__rt__qubit_allocate(); + QirArray* ctrls = quantum__rt__qubit_allocate_array(2); + + quantum__qis__r__body(PauliId_Y, angle, target); + quantum__qis__r__adj(PauliId_Y, angle, target); + quantum__qis__r__ctl(ctrls, PauliId_X, angle, target); + quantum__qis__r__ctladj(ctrls, PauliId_X, angle, target); + + quantum__rt__qubit_release_array(ctrls); + quantum__rt__array_update_reference_count(ctrls, -1); + quantum__rt__qubit_release(target); + + REQUIRE(qapi->rotationAngle == Approx(0).epsilon(0.0001)); +} + +TEST_CASE("Adjoints of Exp should use inverse of the angle", "[qir_support]") +{ + std::unique_ptr qapi = std::make_unique(); + QirContextScope qirctx(qapi.get()); + + const double angle = 0.42; + + QirArray* targets = quantum__rt__qubit_allocate_array(2); + QirArray* ctrls = quantum__rt__qubit_allocate_array(2); + QirArray* axes = quantum__rt__array_create_1d(1 /*element size*/, 2 /*count*/); + axes->buffer[0] = 2; + axes->buffer[1] = 3; + + quantum__qis__exp__body(axes, angle, targets); + quantum__qis__exp__adj(axes, angle, targets); + quantum__qis__exp__ctl(ctrls, axes, angle, targets); + quantum__qis__exp__ctladj(ctrls, axes, angle, targets); + + quantum__rt__qubit_release_array(ctrls); + quantum__rt__array_update_reference_count(ctrls, -1); + quantum__rt__qubit_release_array(targets); + quantum__rt__array_update_reference_count(targets, -1); + + REQUIRE(qapi->exponentAngle == Approx(0).epsilon(0.0001)); +} diff --git a/src/QirRuntime/test/unittests/ToffoliTests.cpp b/src/Qir/Runtime/unittests/ToffoliTests.cpp similarity index 96% rename from src/QirRuntime/test/unittests/ToffoliTests.cpp rename to src/Qir/Runtime/unittests/ToffoliTests.cpp index 84777cacf77..b0fb3643032 100644 --- a/src/QirRuntime/test/unittests/ToffoliTests.cpp +++ b/src/Qir/Runtime/unittests/ToffoliTests.cpp @@ -1,130 +1,130 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include - -#include "catch.hpp" - -#include "QirRuntimeApi_I.hpp" -#include "QSharpSimApi_I.hpp" -#include "SimFactory.hpp" - -using namespace Microsoft::Quantum; - -static Result MZ(IQuantumGateSet* iqa, Qubit q) -{ - PauliId pauliZ[1] = {PauliId_Z}; - Qubit qs[1] = {q}; - return iqa->Measure(1, pauliZ, 1, qs); -} - -TEST_CASE("Basis vector", "[toffoli]") -{ - std::unique_ptr sim = CreateToffoliSimulator(); - IQuantumGateSet* iqa = dynamic_cast(sim.get()); - - constexpr int n = 1000; - std::vector qubits; - qubits.reserve(n); - for (int i = 0; i < n; i++) - { - Qubit q = sim->AllocateQubit(); - qubits.push_back(q); - if ((i & 0x1) == 1) - { - iqa->X(q); - } - } - - long sum = 0; - for (Qubit q : qubits) - { - if (sim->GetResultValue(MZ(iqa, q)) == Result_One) - { - sum++; - } - } - REQUIRE(sum == n / 2); -} - -TEST_CASE("Controlled X", "[toffoli]") -{ - std::unique_ptr sim = CreateToffoliSimulator(); - IQuantumGateSet* iqa = dynamic_cast(sim.get()); - - Qubit q[4]; - q[0] = sim->AllocateQubit(); - q[1] = sim->AllocateQubit(); - q[2] = sim->AllocateQubit(); - q[3] = sim->AllocateQubit(); - - // qubits state: |0000> - iqa->ControlledX(1, &q[0], q[1]); - REQUIRE(sim->GetResultValue(MZ(iqa, q[1])) == Result_Zero); - iqa->ControlledX(2, &q[0], q[2]); - REQUIRE(sim->GetResultValue(MZ(iqa, q[2])) == Result_Zero); - iqa->ControlledX(3, &q[0], q[3]); - REQUIRE(sim->GetResultValue(MZ(iqa, q[2])) == Result_Zero); - - iqa->X(q[0]); - - // qubits state: |1000> - iqa->ControlledX(2, &q[0], q[2]); - REQUIRE(sim->GetResultValue(MZ(iqa, q[2])) == Result_Zero); - iqa->ControlledX(3, &q[0], q[3]); - REQUIRE(sim->GetResultValue(MZ(iqa, q[3])) == Result_Zero); - iqa->ControlledX(1, &q[0], q[2]); - REQUIRE(sim->GetResultValue(MZ(iqa, q[2])) == Result_One); - - // qubits state: |1010> - iqa->ControlledX(3, &q[0], q[3]); - REQUIRE(sim->GetResultValue(MZ(iqa, q[3])) == Result_Zero); - - iqa->X(q[1]); - - // qubits state: |1110> - iqa->ControlledX(2, &q[1], q[3]); - REQUIRE(sim->GetResultValue(MZ(iqa, q[3])) == Result_One); - - // qubits state: |1111> - iqa->ControlledX(3, &q[1], q[0]); - REQUIRE(sim->GetResultValue(MZ(iqa, q[0])) == Result_Zero); -} - -TEST_CASE("Measure and assert probability", "[toffoli]") -{ - std::unique_ptr sim = CreateToffoliSimulator(); - IQuantumGateSet* iqa = dynamic_cast(sim.get()); - - const int count = 3; - Qubit qs[count]; - for (int i = 0; i < count; i++) - { - qs[i] = sim->AllocateQubit(); - } - - PauliId zzz[count] = {PauliId_Z, PauliId_Z, PauliId_Z}; - PauliId ziz[count] = {PauliId_Z, PauliId_I, PauliId_Z}; - - // initial state is |000> - IDiagnostics* idig = dynamic_cast(sim.get()); - REQUIRE(sim->GetResultValue(iqa->Measure(count, zzz, count, qs)) == Result_Zero); - REQUIRE(sim->GetResultValue(iqa->Measure(count, ziz, count, qs)) == Result_Zero); - REQUIRE(idig->Assert(count, zzz, qs, sim->UseZero(), "")); - REQUIRE(idig->AssertProbability(count, zzz, qs, 1.0, 0.01, "")); - - // set state to: |010> - iqa->X(qs[1]); - REQUIRE(sim->GetResultValue(iqa->Measure(count, zzz, count, qs)) == Result_One); - REQUIRE(sim->GetResultValue(iqa->Measure(count, ziz, count, qs)) == Result_Zero); - REQUIRE(idig->Assert(count, zzz, qs, sim->UseOne(), "")); - REQUIRE(idig->AssertProbability(count, ziz, qs, 1.0, 0.01, "")); - - // set state to: |111> - iqa->X(qs[0]); - iqa->X(qs[2]); - REQUIRE(sim->GetResultValue(iqa->Measure(count, zzz, count, qs)) == Result_One); - REQUIRE(sim->GetResultValue(iqa->Measure(count, ziz, count, qs)) == Result_Zero); - REQUIRE(idig->Assert(count, ziz, qs, sim->UseZero(), "")); - REQUIRE(idig->AssertProbability(count, zzz, qs, 0.0, 0.01, "")); +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include + +#include "catch.hpp" + +#include "QirRuntimeApi_I.hpp" +#include "QSharpSimApi_I.hpp" +#include "SimFactory.hpp" + +using namespace Microsoft::Quantum; + +static Result MZ(IQuantumGateSet* iqa, Qubit q) +{ + PauliId pauliZ[1] = {PauliId_Z}; + Qubit qs[1] = {q}; + return iqa->Measure(1, pauliZ, 1, qs); +} + +TEST_CASE("Basis vector", "[toffoli]") +{ + std::unique_ptr sim = CreateToffoliSimulator(); + IQuantumGateSet* iqa = dynamic_cast(sim.get()); + + constexpr int n = 1000; + std::vector qubits; + qubits.reserve(n); + for (int i = 0; i < n; i++) + { + Qubit q = sim->AllocateQubit(); + qubits.push_back(q); + if ((i & 0x1) == 1) + { + iqa->X(q); + } + } + + long sum = 0; + for (Qubit q : qubits) + { + if (sim->GetResultValue(MZ(iqa, q)) == Result_One) + { + sum++; + } + } + REQUIRE(sum == n / 2); +} + +TEST_CASE("Controlled X", "[toffoli]") +{ + std::unique_ptr sim = CreateToffoliSimulator(); + IQuantumGateSet* iqa = dynamic_cast(sim.get()); + + Qubit q[4]; + q[0] = sim->AllocateQubit(); + q[1] = sim->AllocateQubit(); + q[2] = sim->AllocateQubit(); + q[3] = sim->AllocateQubit(); + + // qubits state: |0000> + iqa->ControlledX(1, &q[0], q[1]); + REQUIRE(sim->GetResultValue(MZ(iqa, q[1])) == Result_Zero); + iqa->ControlledX(2, &q[0], q[2]); + REQUIRE(sim->GetResultValue(MZ(iqa, q[2])) == Result_Zero); + iqa->ControlledX(3, &q[0], q[3]); + REQUIRE(sim->GetResultValue(MZ(iqa, q[2])) == Result_Zero); + + iqa->X(q[0]); + + // qubits state: |1000> + iqa->ControlledX(2, &q[0], q[2]); + REQUIRE(sim->GetResultValue(MZ(iqa, q[2])) == Result_Zero); + iqa->ControlledX(3, &q[0], q[3]); + REQUIRE(sim->GetResultValue(MZ(iqa, q[3])) == Result_Zero); + iqa->ControlledX(1, &q[0], q[2]); + REQUIRE(sim->GetResultValue(MZ(iqa, q[2])) == Result_One); + + // qubits state: |1010> + iqa->ControlledX(3, &q[0], q[3]); + REQUIRE(sim->GetResultValue(MZ(iqa, q[3])) == Result_Zero); + + iqa->X(q[1]); + + // qubits state: |1110> + iqa->ControlledX(2, &q[1], q[3]); + REQUIRE(sim->GetResultValue(MZ(iqa, q[3])) == Result_One); + + // qubits state: |1111> + iqa->ControlledX(3, &q[1], q[0]); + REQUIRE(sim->GetResultValue(MZ(iqa, q[0])) == Result_Zero); +} + +TEST_CASE("Measure and assert probability", "[toffoli]") +{ + std::unique_ptr sim = CreateToffoliSimulator(); + IQuantumGateSet* iqa = dynamic_cast(sim.get()); + + const int count = 3; + Qubit qs[count]; + for (int i = 0; i < count; i++) + { + qs[i] = sim->AllocateQubit(); + } + + PauliId zzz[count] = {PauliId_Z, PauliId_Z, PauliId_Z}; + PauliId ziz[count] = {PauliId_Z, PauliId_I, PauliId_Z}; + + // initial state is |000> + IDiagnostics* idig = dynamic_cast(sim.get()); + REQUIRE(sim->GetResultValue(iqa->Measure(count, zzz, count, qs)) == Result_Zero); + REQUIRE(sim->GetResultValue(iqa->Measure(count, ziz, count, qs)) == Result_Zero); + REQUIRE(idig->Assert(count, zzz, qs, sim->UseZero(), "")); + REQUIRE(idig->AssertProbability(count, zzz, qs, 1.0, 0.01, "")); + + // set state to: |010> + iqa->X(qs[1]); + REQUIRE(sim->GetResultValue(iqa->Measure(count, zzz, count, qs)) == Result_One); + REQUIRE(sim->GetResultValue(iqa->Measure(count, ziz, count, qs)) == Result_Zero); + REQUIRE(idig->Assert(count, zzz, qs, sim->UseOne(), "")); + REQUIRE(idig->AssertProbability(count, ziz, qs, 1.0, 0.01, "")); + + // set state to: |111> + iqa->X(qs[0]); + iqa->X(qs[2]); + REQUIRE(sim->GetResultValue(iqa->Measure(count, zzz, count, qs)) == Result_One); + REQUIRE(sim->GetResultValue(iqa->Measure(count, ziz, count, qs)) == Result_Zero); + REQUIRE(idig->Assert(count, ziz, qs, sim->UseZero(), "")); + REQUIRE(idig->AssertProbability(count, zzz, qs, 0.0, 0.01, "")); } \ No newline at end of file diff --git a/src/QirRuntime/test/unittests/TracerTests.cpp b/src/Qir/Runtime/unittests/TracerTests.cpp similarity index 97% rename from src/QirRuntime/test/unittests/TracerTests.cpp rename to src/Qir/Runtime/unittests/TracerTests.cpp index d1ff4711036..802d0a429e8 100644 --- a/src/QirRuntime/test/unittests/TracerTests.cpp +++ b/src/Qir/Runtime/unittests/TracerTests.cpp @@ -1,483 +1,483 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -#include -#include -#include - -#include "catch.hpp" - -#include "CoreTypes.hpp" -#include "tracer.hpp" - -using namespace std; -using namespace Microsoft::Quantum; - -TEST_CASE("Layering distinct single-qubit operations of non-zero durations", "[tracer]") -{ - shared_ptr tr = CreateTracer(3 /*layer duration*/); - - Qubit q1 = tr->AllocateQubit(); - Qubit q2 = tr->AllocateQubit(); - Qubit q3 = tr->AllocateQubit(); - - CHECK(0 == tr->TraceSingleQubitOp(1, 1, q1)); // L(0,3) should be created - CHECK(0 == tr->TraceSingleQubitOp(2, 2, q1)); // add the op into L(0,3) - CHECK(0 == tr->TraceSingleQubitOp(3, 1, q2)); // add the op into L(0,3) - CHECK(1 == tr->TraceSingleQubitOp(4, 3, q2)); // create new layer L(3,3) - CHECK(2 == tr->TraceSingleQubitOp(5, 4, q2)); // long op! create new layer L(6,4) - CHECK(1 == tr->TraceSingleQubitOp(6, 2, q1)); // add the op into L(3,3) - CHECK(0 == tr->TraceSingleQubitOp(7, 1, q3)); // add the op into L(0,3) - CHECK(2 == tr->TraceSingleQubitOp(8, 4, q3)); // long op! but fits into existing L(6,4) - CHECK(3 == tr->TraceSingleQubitOp(9, 5, q1)); // long op! add the op into L(10,5) - - const vector& layers = tr->UseLayers(); - REQUIRE(layers.size() == 4); - CHECK(layers[0].startTime == 0); - CHECK(layers[0].operations.size() == 4); - CHECK(layers[1].startTime == 3); - CHECK(layers[1].operations.size() == 2); - CHECK(layers[2].startTime == 6); - CHECK(layers[2].operations.size() == 2); - CHECK(layers[3].startTime == 10); - CHECK(layers[3].operations.size() == 1); -} - -TEST_CASE("Layering single-qubit operations of zero duration", "[tracer]") -{ - shared_ptr tr = CreateTracer(3 /*layer duration*/); - - Qubit q1 = tr->AllocateQubit(); - Qubit q2 = tr->AllocateQubit(); - Qubit q3 = tr->AllocateQubit(); - - CHECK(0 == tr->TraceSingleQubitOp(1, 1, q1)); // L(0,3) should be created - CHECK(0 == tr->TraceSingleQubitOp(2, 0, q1)); // add the op into L(0,3) - CHECK(INVALID == tr->TraceSingleQubitOp(3, 0, q3)); // pending zero op (will remain orphan) - CHECK(INVALID == tr->TraceSingleQubitOp(4, 0, q2)); // pending zero op - CHECK(INVALID == tr->TraceSingleQubitOp(5, 0, q2)); // another pending zero op - CHECK(0 == tr->TraceSingleQubitOp(6, 1, q2)); // add the op into L(0,3) together with the pending ones - - const vector& layers = tr->UseLayers(); - REQUIRE(layers.size() == 1); - CHECK(layers[0].operations.size() == 5); -} - -TEST_CASE("Layering distinct controlled single-qubit operations", "[tracer]") -{ - shared_ptr tr = CreateTracer(3 /*layer duration*/); - - Qubit q1 = tr->AllocateQubit(); - Qubit q2 = tr->AllocateQubit(); - Qubit q3 = tr->AllocateQubit(); - Qubit q4 = tr->AllocateQubit(); - Qubit q5 = tr->AllocateQubit(); - Qubit q6 = tr->AllocateQubit(); - - CHECK(0 == tr->TraceMultiQubitOp(1, 1, 1 /*nFirst*/, &q1 /*first*/, 1 /*nSecond*/, &q2 /*second*/)); - CHECK(0 == tr->TraceMultiQubitOp(2, 2, 0 /*nFirst*/, nullptr /*first*/, 1 /*nSecond*/, &q2 /*second*/)); - // q2 now is at the limit of the layer duration - - Qubit qs12[2] = {q1, q2}; - CHECK(1 == tr->TraceMultiQubitOp(3, 1, 0 /*nFirst*/, nullptr /*first*/, 2 /*nSecond*/, qs12 /*second*/)); - CHECK(1 == tr->TraceMultiQubitOp(4, 1, 1 /*nFirst*/, &q2 /*first*/, 1 /*nSecond*/, &q3 /*second*/)); - // because of q2, both ops should have been added to a new layer, which now "catches" q1, q2, q3 - - CHECK(0 == tr->TraceMultiQubitOp(5, 0, 1 /*nFirst*/, &q4 /*first*/, 1 /*nSecond*/, &q5 /*second*/)); - CHECK(0 == tr->TraceSingleQubitOp(6, 1, q6)); - // these ops should fall through into the first layer (notice no special handling of duration zero) - - CHECK(1 == tr->TraceMultiQubitOp(7, 1, 1 /*nFirst*/, &q1 /*first*/, 1 /*nSecond*/, &q6 /*second*/)); - CHECK(1 == tr->TraceMultiQubitOp(8, 1, 1 /*nFirst*/, &q3 /*first*/, 1 /*nSecond*/, &q4 /*second*/)); - // because of q1 and q3, thiese ops should be added into the second layer, which now has all but q5 - - CHECK(0 == tr->TraceSingleQubitOp(9, 1, q5)); - // should fall through to the first layer - - Qubit qs46[2] = {q4, q6}; - CHECK(1 == tr->TraceMultiQubitOp(10, 1, 2 /*nFirst*/, qs46 /*first*/, 1 /*nSecond*/, &q5 /*second*/)); - // because of the controls, should be added into the second layer - - const vector& layers = tr->UseLayers(); - REQUIRE(layers.size() == 2); - - CHECK(layers[0].operations.size() == 5); - const auto& ops0 = layers[0].operations; - CHECK(ops0.find(1) != ops0.end()); - CHECK(ops0.find(2) != ops0.end()); - CHECK(ops0.find(5) != ops0.end()); - CHECK(ops0.find(6) != ops0.end()); - CHECK(ops0.find(9) != ops0.end()); - - CHECK(layers[1].operations.size() == 5); - const auto& ops1 = layers[1].operations; - CHECK(ops1.find(3) != ops1.end()); - CHECK(ops1.find(4) != ops1.end()); - CHECK(ops1.find(7) != ops1.end()); - CHECK(ops1.find(8) != ops1.end()); - CHECK(ops1.find(10) != ops1.end()); -} - -// TODO: add multi-qubit ops -TEST_CASE("Operations with same id are counted together", "[tracer]") -{ - shared_ptr tr = CreateTracer(3 /*layer duration*/); - - Qubit q1 = tr->AllocateQubit(); - Qubit q2 = tr->AllocateQubit(); - Qubit q3 = tr->AllocateQubit(); - - // All of these ops should fit into a single layer L(0,3) - tr->TraceSingleQubitOp(1, 1, q1); - tr->TraceSingleQubitOp(2, 2, q1); - tr->TraceSingleQubitOp(1, 1, q2); - tr->TraceSingleQubitOp(2, 1, q2); - tr->TraceSingleQubitOp(1, 1, q2); - tr->TraceSingleQubitOp(3, 2, q3); - - const vector& layers = tr->UseLayers(); - REQUIRE(layers.size() == 1); - CHECK(layers[0].operations.size() == 3); - const auto& ops = layers[0].operations; - CHECK(ops.find(1)->second == 3); - CHECK(ops.find(2)->second == 2); - CHECK(ops.find(3)->second == 1); -} - -TEST_CASE("Global barrier", "[tracer]") -{ - shared_ptr tr = CreateTracer(2 /*layer duration*/); - - Qubit q1 = tr->AllocateQubit(); - Qubit q2 = tr->AllocateQubit(); - Qubit q3 = tr->AllocateQubit(); - Qubit q4 = tr->AllocateQubit(); - - CHECK(0 == tr->TraceSingleQubitOp(1, 4, q1)); // L(0,4) created - CHECK(0 == tr->TraceSingleQubitOp(2, 1, q4)); // added to L(0,4) - CHECK(1 == tr->InjectGlobalBarrier(42, 1)); // creates L(4,2) - - CHECK(2 == tr->TraceMultiQubitOp(3, 1, 1 /*nFirst*/, &q2 /*first*/, 1 /*nSecond*/, &q3 /*second*/)); - // the barrier shouldn't allow this op to fall through into L(0,4), so should create L(6,2) - - CHECK(INVALID == tr->TraceSingleQubitOp(4, 0, q1)); - // the barrier shouldn't allow this op to fall through into L(0,4), so should create pending op - - CHECK(2 == tr->TraceSingleQubitOp(5, 1, q1)); - // should be added into L(6,2) together with the pending op `3` - - CHECK(3 == tr->TraceSingleQubitOp(6, 3, q2)); - // long op, with no existing wide layers to host it, so should create L(8,3) - - CHECK(3 == tr->TraceSingleQubitOp(7, 3, q4)); - // long op but can be added into L(8,3), which is post the barrier - - const vector& layers = tr->UseLayers(); - REQUIRE(layers.size() == 4); - CHECK(layers[0].operations.size() == 2); - CHECK(layers[1].operations.size() == 0); - CHECK(layers[2].operations.size() == 3); - CHECK(layers[3].operations.size() == 2); - - const auto& ops0 = layers[0].operations; - CHECK(ops0.find(1) != ops0.end()); - CHECK(ops0.find(2) != ops0.end()); - - CHECK(42 == layers[1].barrierId); - - const auto& ops2 = layers[2].operations; - CHECK(ops2.find(3) != ops2.end()); - CHECK(ops2.find(4) != ops2.end()); - CHECK(ops2.find(5) != ops2.end()); - - const auto& ops3 = layers[3].operations; - CHECK(ops3.find(6) != ops3.end()); - CHECK(ops3.find(7) != ops3.end()); -} - -// For layering purposes, measurements behave pretty much the same as other operations -TEST_CASE("Layering measurements", "[tracer]") -{ - shared_ptr tr = CreateTracer(1 /*layer duration*/); - - Qubit q1 = tr->AllocateQubit(); - Qubit q2 = tr->AllocateQubit(); - Qubit q3 = tr->AllocateQubit(); - Qubit q4 = tr->AllocateQubit(); - - CHECK(0 == tr->GetLayerIdOfSourceMeasurement(tr->TraceSingleQubitMeasurement(1, 1, q1))); - Qubit qs12[2] = {q1, q2}; - CHECK(1 == tr->GetLayerIdOfSourceMeasurement(tr->TraceMultiQubitMeasurement(2, 1, 2, qs12))); - CHECK(0 == tr->TraceSingleQubitOp(3, 1, q4)); - CHECK(0 == tr->GetLayerIdOfSourceMeasurement(tr->TraceSingleQubitMeasurement(4, 1, q3))); - Qubit qs23[2] = {q2, q3}; - CHECK(2 == tr->GetLayerIdOfSourceMeasurement(tr->TraceMultiQubitMeasurement(5, 1, 2, qs23))); - CHECK(1 == tr->TraceSingleQubitOp(3, 1, q4)); -} - -TEST_CASE("Conditionals: noops", "[tracer][tracer.conditionals]") -{ - shared_ptr tr = CreateTracer(3 /*layer duration*/); - - Qubit q1 = tr->AllocateQubit(); - Qubit q2 = tr->AllocateQubit(); - - CHECK(0 == tr->TraceSingleQubitOp(1, 3, q1)); - CHECK(1 == tr->TraceSingleQubitOp(1, 3, q1)); - Result one = tr->UseOne(); - { - CTracer::FenceScope fs(tr.get(), 1, &one, 0, nullptr); - CHECK(0 == tr->TraceSingleQubitOp(1, 1, q2)); - } - { - CTracer::FenceScope fs(tr.get(), 0, nullptr, 1, &one); - CHECK(0 == tr->TraceSingleQubitOp(1, 1, q2)); - } - { - CTracer::FenceScope fs(tr.get(), 0, nullptr, 0, nullptr); - CHECK(0 == tr->TraceSingleQubitOp(1, 1, q2)); - } -} - -TEST_CASE("Conditionals: a new layer because of the fence", "[tracer][tracer.conditionals]") -{ - shared_ptr tr = CreateTracer(1 /*layer duration*/); - - Qubit q1 = tr->AllocateQubit(); - Qubit q2 = tr->AllocateQubit(); - Qubit q3 = tr->AllocateQubit(); - - CHECK(0 == tr->TraceSingleQubitOp(1, 1, q1)); - Result r = tr->TraceSingleQubitMeasurement(1, 1, q1); - CHECK(1 == tr->GetLayerIdOfSourceMeasurement(r)); - - { - CTracer::FenceScope fs(tr.get(), 1, &r, 0, nullptr); - CHECK(2 == tr->TraceSingleQubitOp(1, 1, q2)); - } - - CHECK(0 == tr->TraceSingleQubitOp(1, 1, q3)); -} - -TEST_CASE("Conditionals: single fence", "[tracer][tracer.conditionals]") -{ - shared_ptr tr = CreateTracer(1 /*layer duration*/); - - Qubit q1 = tr->AllocateQubit(); - Qubit q2 = tr->AllocateQubit(); - Qubit q3 = tr->AllocateQubit(); - - CHECK(0 == tr->TraceSingleQubitOp(1, 1, q1)); - Result r = tr->TraceSingleQubitMeasurement(1, 1, q1); - CHECK(1 == tr->GetLayerIdOfSourceMeasurement(r)); - CHECK(2 == tr->TraceSingleQubitOp(1, 1, q1)); - - { - CTracer::FenceScope fs(tr.get(), 1, &r, 0, nullptr); - CHECK(2 == tr->TraceSingleQubitOp(1, 1, q2)); - } - - CHECK(3 == tr->TraceSingleQubitOp(1, 1, q1)); - CHECK(3 == tr->TraceSingleQubitOp(1, 1, q2)); - CHECK(0 == tr->TraceSingleQubitOp(1, 1, q3)); - CHECK(1 == tr->TraceSingleQubitOp(1, 1, q3)); - CHECK(2 == tr->TraceSingleQubitOp(1, 1, q3)); -} - -TEST_CASE("Conditionals: fence from two result arrays", "[tracer][tracer.conditionals]") -{ - shared_ptr tr = CreateTracer(1 /*layer duration*/); - - Qubit q1 = tr->AllocateQubit(); - Qubit q2 = tr->AllocateQubit(); - Qubit q3 = tr->AllocateQubit(); - - CHECK(0 == tr->TraceSingleQubitOp(1, 1, q1)); - Result r1 = tr->TraceSingleQubitMeasurement(1, 1, q1); - CHECK(1 == tr->GetLayerIdOfSourceMeasurement(r1)); - CHECK(0 == tr->TraceSingleQubitOp(1, 1, q2)); - CHECK(1 == tr->TraceSingleQubitOp(1, 1, q2)); - Result r2 = tr->TraceSingleQubitMeasurement(1, 1, q2); - CHECK(2 == tr->GetLayerIdOfSourceMeasurement(r2)); - - { - CTracer::FenceScope fs(tr.get(), 1, &r1, 1, &r2); - CHECK(3 == tr->TraceSingleQubitOp(1, 1, q3)); - } - - CHECK(2 == tr->TraceSingleQubitOp(1, 1, q1)); -} - -TEST_CASE("Conditionals: nested fence is later than parent", "[tracer][tracer.conditionals]") -{ - shared_ptr tr = CreateTracer(1 /*layer duration*/); - - Qubit q1 = tr->AllocateQubit(); - Qubit q2 = tr->AllocateQubit(); - Qubit q3 = tr->AllocateQubit(); - Qubit q4 = tr->AllocateQubit(); - Qubit q5 = tr->AllocateQubit(); - - CHECK(0 == tr->TraceSingleQubitOp(1, 1, q1)); - Result r1 = tr->TraceSingleQubitMeasurement(1, 1, q1); - CHECK(1 == tr->GetLayerIdOfSourceMeasurement(r1)); - CHECK(0 == tr->TraceSingleQubitOp(1, 1, q2)); - CHECK(1 == tr->TraceSingleQubitOp(1, 1, q2)); - Result r2 = tr->TraceSingleQubitMeasurement(1, 1, q2); - CHECK(2 == tr->GetLayerIdOfSourceMeasurement(r2)); - - { - CTracer::FenceScope fs(tr.get(), 1, &r1, 0, nullptr); - CHECK(2 == tr->TraceSingleQubitOp(1, 1, q3)); - { - CTracer::FenceScope fs(tr.get(), 0, nullptr, 1, &r2); - CHECK(3 == tr->TraceSingleQubitOp(1, 1, q4)); - } - CHECK(2 == tr->TraceSingleQubitOp(1, 1, q5)); - } - - CHECK(2 == tr->TraceSingleQubitOp(1, 1, q1)); -} - -TEST_CASE("Conditionals: nested fence is earlier than parent", "[tracer][tracer.conditionals]") -{ - shared_ptr tr = CreateTracer(1 /*layer duration*/); - - Qubit q1 = tr->AllocateQubit(); - Qubit q2 = tr->AllocateQubit(); - Qubit q3 = tr->AllocateQubit(); - Qubit q4 = tr->AllocateQubit(); - Qubit q5 = tr->AllocateQubit(); - - CHECK(0 == tr->TraceSingleQubitOp(1, 1, q1)); - Result r1 = tr->TraceSingleQubitMeasurement(1, 1, q1); - CHECK(1 == tr->GetLayerIdOfSourceMeasurement(r1)); - CHECK(0 == tr->TraceSingleQubitOp(1, 1, q2)); - CHECK(1 == tr->TraceSingleQubitOp(1, 1, q2)); - Result r2 = tr->TraceSingleQubitMeasurement(1, 1, q2); - CHECK(2 == tr->GetLayerIdOfSourceMeasurement(r2)); - - { - CTracer::FenceScope fs(tr.get(), 1, &r2, 0, nullptr); - CHECK(3 == tr->TraceSingleQubitOp(1, 1, q3)); - { - CTracer::FenceScope fs(tr.get(), 0, nullptr, 1, &r1); - CHECK(3 == tr->TraceSingleQubitOp(1, 1, q4)); - } - CHECK(3 == tr->TraceSingleQubitOp(1, 1, q5)); - } - CHECK(2 == tr->TraceSingleQubitOp(1, 1, q1)); -} - -TEST_CASE("Conditionals: fences and barriers", "[tracer][tracer.conditionals]") -{ - shared_ptr tr = CreateTracer(1 /*layer duration*/); - - Qubit q1 = tr->AllocateQubit(); - Qubit q2 = tr->AllocateQubit(); - Qubit q3 = tr->AllocateQubit(); - Qubit q4 = tr->AllocateQubit(); - Qubit q5 = tr->AllocateQubit(); - - CHECK(0 == tr->TraceSingleQubitOp(1, 1, q1)); - Result r1 = tr->TraceSingleQubitMeasurement(1, 1, q1); - CHECK(1 == tr->GetLayerIdOfSourceMeasurement(r1)); - - CHECK(2 == tr->InjectGlobalBarrier(42, 1)); - - Result r2 = tr->TraceSingleQubitMeasurement(1, 1, q2); - CHECK(3 == tr->GetLayerIdOfSourceMeasurement(r2)); - - { - CTracer::FenceScope fs(tr.get(), 1, &r1, 0, nullptr); - CHECK(3 == tr->TraceSingleQubitOp(1, 1, q3)); - } - { - CTracer::FenceScope fs(tr.get(), 0, nullptr, 1, &r2); - CHECK(4 == tr->TraceSingleQubitOp(1, 1, q4)); - } - CHECK(3 == tr->TraceSingleQubitOp(1, 1, q5)); -} - -TEST_CASE("Output: to string", "[tracer]") -{ - std::unordered_map opNames = {{1, "X"}, {2, "Y"}, {3, "Z"}, {4, "b"}}; - shared_ptr tr = CreateTracer(1 /*layer duration*/, opNames); - - Qubit q1 = tr->AllocateQubit(); - tr->TraceSingleQubitOp(3, 1, q1); - tr->TraceSingleQubitOp(5, 1, q1); - tr->InjectGlobalBarrier(4, 2); - tr->TraceSingleQubitOp(3, 4, q1); - tr->TraceSingleQubitOp(2, 1, q1); - - { - std::stringstream out; - tr->PrintLayerMetrics(out, ",", true /*printZeroMetrics*/); - std::string metrics = out.str(); - - std::stringstream expected; - expected << "layer_id,name,Y,Z,5" << std::endl; - expected << "0,,0,1,0" << std::endl; - expected << "1,,0,0,1" << std::endl; - expected << "2,b,0,0,0" << std::endl; - expected << "4,,0,1,0" << std::endl; - expected << "8,,1,0,0" << std::endl; - - INFO(metrics); - CHECK(metrics == expected.str()); - } - - { - std::stringstream out; - tr->PrintLayerMetrics(out, ",", false /*printZeroMetrics*/); - std::string metrics = out.str(); - - std::stringstream expected; - expected << "layer_id,name,Y,Z,5" << std::endl; - expected << "0,,,1," << std::endl; - expected << "1,,,,1" << std::endl; - expected << "2,b,,," << std::endl; - expected << "4,,,1," << std::endl; - expected << "8,,1,," << std::endl; - - INFO(metrics); - CHECK(metrics == expected.str()); - } -} - -TEST_CASE("Output: to file", "[tracer]") -{ - std::unordered_map opNames = {{1, "X"}, {2, "Y"}, {3, "Z"}, {4, "b"}}; - shared_ptr tr = CreateTracer(1 /*layer duration*/, opNames); - - Qubit q1 = tr->AllocateQubit(); - tr->TraceSingleQubitOp(3, 1, q1); - tr->TraceSingleQubitOp(5, 1, q1); - tr->InjectGlobalBarrier(4, 2); - tr->TraceSingleQubitOp(3, 4, q1); - tr->TraceSingleQubitOp(2, 1, q1); - - const std::string fileName = "tracer-test.txt"; - std::ofstream out; - out.open(fileName); - tr->PrintLayerMetrics(out, "\t", false /*printZeroMetrics*/); - out.close(); - - std::ifstream in(fileName); - string line; - REQUIRE(in.is_open()); - std::string metrics(std::istreambuf_iterator{in}, {}); - in.close(); - - std::stringstream expected; - expected << "layer_id\tname\tY\tZ\t5" << std::endl; - expected << "0\t\t\t1\t" << std::endl; - expected << "1\t\t\t\t1" << std::endl; - expected << "2\tb\t\t\t" << std::endl; - expected << "4\t\t\t1\t" << std::endl; - expected << "8\t\t1\t\t" << std::endl; - - INFO(metrics); - CHECK(metrics == expected.str()); -} +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include +#include +#include + +#include "catch.hpp" + +#include "CoreTypes.hpp" +#include "tracer.hpp" + +using namespace std; +using namespace Microsoft::Quantum; + +TEST_CASE("Layering distinct single-qubit operations of non-zero durations", "[tracer]") +{ + shared_ptr tr = CreateTracer(3 /*layer duration*/); + + Qubit q1 = tr->AllocateQubit(); + Qubit q2 = tr->AllocateQubit(); + Qubit q3 = tr->AllocateQubit(); + + CHECK(0 == tr->TraceSingleQubitOp(1, 1, q1)); // L(0,3) should be created + CHECK(0 == tr->TraceSingleQubitOp(2, 2, q1)); // add the op into L(0,3) + CHECK(0 == tr->TraceSingleQubitOp(3, 1, q2)); // add the op into L(0,3) + CHECK(1 == tr->TraceSingleQubitOp(4, 3, q2)); // create new layer L(3,3) + CHECK(2 == tr->TraceSingleQubitOp(5, 4, q2)); // long op! create new layer L(6,4) + CHECK(1 == tr->TraceSingleQubitOp(6, 2, q1)); // add the op into L(3,3) + CHECK(0 == tr->TraceSingleQubitOp(7, 1, q3)); // add the op into L(0,3) + CHECK(2 == tr->TraceSingleQubitOp(8, 4, q3)); // long op! but fits into existing L(6,4) + CHECK(3 == tr->TraceSingleQubitOp(9, 5, q1)); // long op! add the op into L(10,5) + + const vector& layers = tr->UseLayers(); + REQUIRE(layers.size() == 4); + CHECK(layers[0].startTime == 0); + CHECK(layers[0].operations.size() == 4); + CHECK(layers[1].startTime == 3); + CHECK(layers[1].operations.size() == 2); + CHECK(layers[2].startTime == 6); + CHECK(layers[2].operations.size() == 2); + CHECK(layers[3].startTime == 10); + CHECK(layers[3].operations.size() == 1); +} + +TEST_CASE("Layering single-qubit operations of zero duration", "[tracer]") +{ + shared_ptr tr = CreateTracer(3 /*layer duration*/); + + Qubit q1 = tr->AllocateQubit(); + Qubit q2 = tr->AllocateQubit(); + Qubit q3 = tr->AllocateQubit(); + + CHECK(0 == tr->TraceSingleQubitOp(1, 1, q1)); // L(0,3) should be created + CHECK(0 == tr->TraceSingleQubitOp(2, 0, q1)); // add the op into L(0,3) + CHECK(INVALID == tr->TraceSingleQubitOp(3, 0, q3)); // pending zero op (will remain orphan) + CHECK(INVALID == tr->TraceSingleQubitOp(4, 0, q2)); // pending zero op + CHECK(INVALID == tr->TraceSingleQubitOp(5, 0, q2)); // another pending zero op + CHECK(0 == tr->TraceSingleQubitOp(6, 1, q2)); // add the op into L(0,3) together with the pending ones + + const vector& layers = tr->UseLayers(); + REQUIRE(layers.size() == 1); + CHECK(layers[0].operations.size() == 5); +} + +TEST_CASE("Layering distinct controlled single-qubit operations", "[tracer]") +{ + shared_ptr tr = CreateTracer(3 /*layer duration*/); + + Qubit q1 = tr->AllocateQubit(); + Qubit q2 = tr->AllocateQubit(); + Qubit q3 = tr->AllocateQubit(); + Qubit q4 = tr->AllocateQubit(); + Qubit q5 = tr->AllocateQubit(); + Qubit q6 = tr->AllocateQubit(); + + CHECK(0 == tr->TraceMultiQubitOp(1, 1, 1 /*nFirst*/, &q1 /*first*/, 1 /*nSecond*/, &q2 /*second*/)); + CHECK(0 == tr->TraceMultiQubitOp(2, 2, 0 /*nFirst*/, nullptr /*first*/, 1 /*nSecond*/, &q2 /*second*/)); + // q2 now is at the limit of the layer duration + + Qubit qs12[2] = {q1, q2}; + CHECK(1 == tr->TraceMultiQubitOp(3, 1, 0 /*nFirst*/, nullptr /*first*/, 2 /*nSecond*/, qs12 /*second*/)); + CHECK(1 == tr->TraceMultiQubitOp(4, 1, 1 /*nFirst*/, &q2 /*first*/, 1 /*nSecond*/, &q3 /*second*/)); + // because of q2, both ops should have been added to a new layer, which now "catches" q1, q2, q3 + + CHECK(0 == tr->TraceMultiQubitOp(5, 0, 1 /*nFirst*/, &q4 /*first*/, 1 /*nSecond*/, &q5 /*second*/)); + CHECK(0 == tr->TraceSingleQubitOp(6, 1, q6)); + // these ops should fall through into the first layer (notice no special handling of duration zero) + + CHECK(1 == tr->TraceMultiQubitOp(7, 1, 1 /*nFirst*/, &q1 /*first*/, 1 /*nSecond*/, &q6 /*second*/)); + CHECK(1 == tr->TraceMultiQubitOp(8, 1, 1 /*nFirst*/, &q3 /*first*/, 1 /*nSecond*/, &q4 /*second*/)); + // because of q1 and q3, thiese ops should be added into the second layer, which now has all but q5 + + CHECK(0 == tr->TraceSingleQubitOp(9, 1, q5)); + // should fall through to the first layer + + Qubit qs46[2] = {q4, q6}; + CHECK(1 == tr->TraceMultiQubitOp(10, 1, 2 /*nFirst*/, qs46 /*first*/, 1 /*nSecond*/, &q5 /*second*/)); + // because of the controls, should be added into the second layer + + const vector& layers = tr->UseLayers(); + REQUIRE(layers.size() == 2); + + CHECK(layers[0].operations.size() == 5); + const auto& ops0 = layers[0].operations; + CHECK(ops0.find(1) != ops0.end()); + CHECK(ops0.find(2) != ops0.end()); + CHECK(ops0.find(5) != ops0.end()); + CHECK(ops0.find(6) != ops0.end()); + CHECK(ops0.find(9) != ops0.end()); + + CHECK(layers[1].operations.size() == 5); + const auto& ops1 = layers[1].operations; + CHECK(ops1.find(3) != ops1.end()); + CHECK(ops1.find(4) != ops1.end()); + CHECK(ops1.find(7) != ops1.end()); + CHECK(ops1.find(8) != ops1.end()); + CHECK(ops1.find(10) != ops1.end()); +} + +// TODO: add multi-qubit ops +TEST_CASE("Operations with same id are counted together", "[tracer]") +{ + shared_ptr tr = CreateTracer(3 /*layer duration*/); + + Qubit q1 = tr->AllocateQubit(); + Qubit q2 = tr->AllocateQubit(); + Qubit q3 = tr->AllocateQubit(); + + // All of these ops should fit into a single layer L(0,3) + tr->TraceSingleQubitOp(1, 1, q1); + tr->TraceSingleQubitOp(2, 2, q1); + tr->TraceSingleQubitOp(1, 1, q2); + tr->TraceSingleQubitOp(2, 1, q2); + tr->TraceSingleQubitOp(1, 1, q2); + tr->TraceSingleQubitOp(3, 2, q3); + + const vector& layers = tr->UseLayers(); + REQUIRE(layers.size() == 1); + CHECK(layers[0].operations.size() == 3); + const auto& ops = layers[0].operations; + CHECK(ops.find(1)->second == 3); + CHECK(ops.find(2)->second == 2); + CHECK(ops.find(3)->second == 1); +} + +TEST_CASE("Global barrier", "[tracer]") +{ + shared_ptr tr = CreateTracer(2 /*layer duration*/); + + Qubit q1 = tr->AllocateQubit(); + Qubit q2 = tr->AllocateQubit(); + Qubit q3 = tr->AllocateQubit(); + Qubit q4 = tr->AllocateQubit(); + + CHECK(0 == tr->TraceSingleQubitOp(1, 4, q1)); // L(0,4) created + CHECK(0 == tr->TraceSingleQubitOp(2, 1, q4)); // added to L(0,4) + CHECK(1 == tr->InjectGlobalBarrier(42, 1)); // creates L(4,2) + + CHECK(2 == tr->TraceMultiQubitOp(3, 1, 1 /*nFirst*/, &q2 /*first*/, 1 /*nSecond*/, &q3 /*second*/)); + // the barrier shouldn't allow this op to fall through into L(0,4), so should create L(6,2) + + CHECK(INVALID == tr->TraceSingleQubitOp(4, 0, q1)); + // the barrier shouldn't allow this op to fall through into L(0,4), so should create pending op + + CHECK(2 == tr->TraceSingleQubitOp(5, 1, q1)); + // should be added into L(6,2) together with the pending op `3` + + CHECK(3 == tr->TraceSingleQubitOp(6, 3, q2)); + // long op, with no existing wide layers to host it, so should create L(8,3) + + CHECK(3 == tr->TraceSingleQubitOp(7, 3, q4)); + // long op but can be added into L(8,3), which is post the barrier + + const vector& layers = tr->UseLayers(); + REQUIRE(layers.size() == 4); + CHECK(layers[0].operations.size() == 2); + CHECK(layers[1].operations.size() == 0); + CHECK(layers[2].operations.size() == 3); + CHECK(layers[3].operations.size() == 2); + + const auto& ops0 = layers[0].operations; + CHECK(ops0.find(1) != ops0.end()); + CHECK(ops0.find(2) != ops0.end()); + + CHECK(42 == layers[1].barrierId); + + const auto& ops2 = layers[2].operations; + CHECK(ops2.find(3) != ops2.end()); + CHECK(ops2.find(4) != ops2.end()); + CHECK(ops2.find(5) != ops2.end()); + + const auto& ops3 = layers[3].operations; + CHECK(ops3.find(6) != ops3.end()); + CHECK(ops3.find(7) != ops3.end()); +} + +// For layering purposes, measurements behave pretty much the same as other operations +TEST_CASE("Layering measurements", "[tracer]") +{ + shared_ptr tr = CreateTracer(1 /*layer duration*/); + + Qubit q1 = tr->AllocateQubit(); + Qubit q2 = tr->AllocateQubit(); + Qubit q3 = tr->AllocateQubit(); + Qubit q4 = tr->AllocateQubit(); + + CHECK(0 == tr->GetLayerIdOfSourceMeasurement(tr->TraceSingleQubitMeasurement(1, 1, q1))); + Qubit qs12[2] = {q1, q2}; + CHECK(1 == tr->GetLayerIdOfSourceMeasurement(tr->TraceMultiQubitMeasurement(2, 1, 2, qs12))); + CHECK(0 == tr->TraceSingleQubitOp(3, 1, q4)); + CHECK(0 == tr->GetLayerIdOfSourceMeasurement(tr->TraceSingleQubitMeasurement(4, 1, q3))); + Qubit qs23[2] = {q2, q3}; + CHECK(2 == tr->GetLayerIdOfSourceMeasurement(tr->TraceMultiQubitMeasurement(5, 1, 2, qs23))); + CHECK(1 == tr->TraceSingleQubitOp(3, 1, q4)); +} + +TEST_CASE("Conditionals: noops", "[tracer][tracer.conditionals]") +{ + shared_ptr tr = CreateTracer(3 /*layer duration*/); + + Qubit q1 = tr->AllocateQubit(); + Qubit q2 = tr->AllocateQubit(); + + CHECK(0 == tr->TraceSingleQubitOp(1, 3, q1)); + CHECK(1 == tr->TraceSingleQubitOp(1, 3, q1)); + Result one = tr->UseOne(); + { + CTracer::FenceScope fs(tr.get(), 1, &one, 0, nullptr); + CHECK(0 == tr->TraceSingleQubitOp(1, 1, q2)); + } + { + CTracer::FenceScope fs(tr.get(), 0, nullptr, 1, &one); + CHECK(0 == tr->TraceSingleQubitOp(1, 1, q2)); + } + { + CTracer::FenceScope fs(tr.get(), 0, nullptr, 0, nullptr); + CHECK(0 == tr->TraceSingleQubitOp(1, 1, q2)); + } +} + +TEST_CASE("Conditionals: a new layer because of the fence", "[tracer][tracer.conditionals]") +{ + shared_ptr tr = CreateTracer(1 /*layer duration*/); + + Qubit q1 = tr->AllocateQubit(); + Qubit q2 = tr->AllocateQubit(); + Qubit q3 = tr->AllocateQubit(); + + CHECK(0 == tr->TraceSingleQubitOp(1, 1, q1)); + Result r = tr->TraceSingleQubitMeasurement(1, 1, q1); + CHECK(1 == tr->GetLayerIdOfSourceMeasurement(r)); + + { + CTracer::FenceScope fs(tr.get(), 1, &r, 0, nullptr); + CHECK(2 == tr->TraceSingleQubitOp(1, 1, q2)); + } + + CHECK(0 == tr->TraceSingleQubitOp(1, 1, q3)); +} + +TEST_CASE("Conditionals: single fence", "[tracer][tracer.conditionals]") +{ + shared_ptr tr = CreateTracer(1 /*layer duration*/); + + Qubit q1 = tr->AllocateQubit(); + Qubit q2 = tr->AllocateQubit(); + Qubit q3 = tr->AllocateQubit(); + + CHECK(0 == tr->TraceSingleQubitOp(1, 1, q1)); + Result r = tr->TraceSingleQubitMeasurement(1, 1, q1); + CHECK(1 == tr->GetLayerIdOfSourceMeasurement(r)); + CHECK(2 == tr->TraceSingleQubitOp(1, 1, q1)); + + { + CTracer::FenceScope fs(tr.get(), 1, &r, 0, nullptr); + CHECK(2 == tr->TraceSingleQubitOp(1, 1, q2)); + } + + CHECK(3 == tr->TraceSingleQubitOp(1, 1, q1)); + CHECK(3 == tr->TraceSingleQubitOp(1, 1, q2)); + CHECK(0 == tr->TraceSingleQubitOp(1, 1, q3)); + CHECK(1 == tr->TraceSingleQubitOp(1, 1, q3)); + CHECK(2 == tr->TraceSingleQubitOp(1, 1, q3)); +} + +TEST_CASE("Conditionals: fence from two result arrays", "[tracer][tracer.conditionals]") +{ + shared_ptr tr = CreateTracer(1 /*layer duration*/); + + Qubit q1 = tr->AllocateQubit(); + Qubit q2 = tr->AllocateQubit(); + Qubit q3 = tr->AllocateQubit(); + + CHECK(0 == tr->TraceSingleQubitOp(1, 1, q1)); + Result r1 = tr->TraceSingleQubitMeasurement(1, 1, q1); + CHECK(1 == tr->GetLayerIdOfSourceMeasurement(r1)); + CHECK(0 == tr->TraceSingleQubitOp(1, 1, q2)); + CHECK(1 == tr->TraceSingleQubitOp(1, 1, q2)); + Result r2 = tr->TraceSingleQubitMeasurement(1, 1, q2); + CHECK(2 == tr->GetLayerIdOfSourceMeasurement(r2)); + + { + CTracer::FenceScope fs(tr.get(), 1, &r1, 1, &r2); + CHECK(3 == tr->TraceSingleQubitOp(1, 1, q3)); + } + + CHECK(2 == tr->TraceSingleQubitOp(1, 1, q1)); +} + +TEST_CASE("Conditionals: nested fence is later than parent", "[tracer][tracer.conditionals]") +{ + shared_ptr tr = CreateTracer(1 /*layer duration*/); + + Qubit q1 = tr->AllocateQubit(); + Qubit q2 = tr->AllocateQubit(); + Qubit q3 = tr->AllocateQubit(); + Qubit q4 = tr->AllocateQubit(); + Qubit q5 = tr->AllocateQubit(); + + CHECK(0 == tr->TraceSingleQubitOp(1, 1, q1)); + Result r1 = tr->TraceSingleQubitMeasurement(1, 1, q1); + CHECK(1 == tr->GetLayerIdOfSourceMeasurement(r1)); + CHECK(0 == tr->TraceSingleQubitOp(1, 1, q2)); + CHECK(1 == tr->TraceSingleQubitOp(1, 1, q2)); + Result r2 = tr->TraceSingleQubitMeasurement(1, 1, q2); + CHECK(2 == tr->GetLayerIdOfSourceMeasurement(r2)); + + { + CTracer::FenceScope fs(tr.get(), 1, &r1, 0, nullptr); + CHECK(2 == tr->TraceSingleQubitOp(1, 1, q3)); + { + CTracer::FenceScope fs(tr.get(), 0, nullptr, 1, &r2); + CHECK(3 == tr->TraceSingleQubitOp(1, 1, q4)); + } + CHECK(2 == tr->TraceSingleQubitOp(1, 1, q5)); + } + + CHECK(2 == tr->TraceSingleQubitOp(1, 1, q1)); +} + +TEST_CASE("Conditionals: nested fence is earlier than parent", "[tracer][tracer.conditionals]") +{ + shared_ptr tr = CreateTracer(1 /*layer duration*/); + + Qubit q1 = tr->AllocateQubit(); + Qubit q2 = tr->AllocateQubit(); + Qubit q3 = tr->AllocateQubit(); + Qubit q4 = tr->AllocateQubit(); + Qubit q5 = tr->AllocateQubit(); + + CHECK(0 == tr->TraceSingleQubitOp(1, 1, q1)); + Result r1 = tr->TraceSingleQubitMeasurement(1, 1, q1); + CHECK(1 == tr->GetLayerIdOfSourceMeasurement(r1)); + CHECK(0 == tr->TraceSingleQubitOp(1, 1, q2)); + CHECK(1 == tr->TraceSingleQubitOp(1, 1, q2)); + Result r2 = tr->TraceSingleQubitMeasurement(1, 1, q2); + CHECK(2 == tr->GetLayerIdOfSourceMeasurement(r2)); + + { + CTracer::FenceScope fs(tr.get(), 1, &r2, 0, nullptr); + CHECK(3 == tr->TraceSingleQubitOp(1, 1, q3)); + { + CTracer::FenceScope fs(tr.get(), 0, nullptr, 1, &r1); + CHECK(3 == tr->TraceSingleQubitOp(1, 1, q4)); + } + CHECK(3 == tr->TraceSingleQubitOp(1, 1, q5)); + } + CHECK(2 == tr->TraceSingleQubitOp(1, 1, q1)); +} + +TEST_CASE("Conditionals: fences and barriers", "[tracer][tracer.conditionals]") +{ + shared_ptr tr = CreateTracer(1 /*layer duration*/); + + Qubit q1 = tr->AllocateQubit(); + Qubit q2 = tr->AllocateQubit(); + Qubit q3 = tr->AllocateQubit(); + Qubit q4 = tr->AllocateQubit(); + Qubit q5 = tr->AllocateQubit(); + + CHECK(0 == tr->TraceSingleQubitOp(1, 1, q1)); + Result r1 = tr->TraceSingleQubitMeasurement(1, 1, q1); + CHECK(1 == tr->GetLayerIdOfSourceMeasurement(r1)); + + CHECK(2 == tr->InjectGlobalBarrier(42, 1)); + + Result r2 = tr->TraceSingleQubitMeasurement(1, 1, q2); + CHECK(3 == tr->GetLayerIdOfSourceMeasurement(r2)); + + { + CTracer::FenceScope fs(tr.get(), 1, &r1, 0, nullptr); + CHECK(3 == tr->TraceSingleQubitOp(1, 1, q3)); + } + { + CTracer::FenceScope fs(tr.get(), 0, nullptr, 1, &r2); + CHECK(4 == tr->TraceSingleQubitOp(1, 1, q4)); + } + CHECK(3 == tr->TraceSingleQubitOp(1, 1, q5)); +} + +TEST_CASE("Output: to string", "[tracer]") +{ + std::unordered_map opNames = {{1, "X"}, {2, "Y"}, {3, "Z"}, {4, "b"}}; + shared_ptr tr = CreateTracer(1 /*layer duration*/, opNames); + + Qubit q1 = tr->AllocateQubit(); + tr->TraceSingleQubitOp(3, 1, q1); + tr->TraceSingleQubitOp(5, 1, q1); + tr->InjectGlobalBarrier(4, 2); + tr->TraceSingleQubitOp(3, 4, q1); + tr->TraceSingleQubitOp(2, 1, q1); + + { + std::stringstream out; + tr->PrintLayerMetrics(out, ",", true /*printZeroMetrics*/); + std::string metrics = out.str(); + + std::stringstream expected; + expected << "layer_id,name,Y,Z,5" << std::endl; + expected << "0,,0,1,0" << std::endl; + expected << "1,,0,0,1" << std::endl; + expected << "2,b,0,0,0" << std::endl; + expected << "4,,0,1,0" << std::endl; + expected << "8,,1,0,0" << std::endl; + + INFO(metrics); + CHECK(metrics == expected.str()); + } + + { + std::stringstream out; + tr->PrintLayerMetrics(out, ",", false /*printZeroMetrics*/); + std::string metrics = out.str(); + + std::stringstream expected; + expected << "layer_id,name,Y,Z,5" << std::endl; + expected << "0,,,1," << std::endl; + expected << "1,,,,1" << std::endl; + expected << "2,b,,," << std::endl; + expected << "4,,,1," << std::endl; + expected << "8,,1,," << std::endl; + + INFO(metrics); + CHECK(metrics == expected.str()); + } +} + +TEST_CASE("Output: to file", "[tracer]") +{ + std::unordered_map opNames = {{1, "X"}, {2, "Y"}, {3, "Z"}, {4, "b"}}; + shared_ptr tr = CreateTracer(1 /*layer duration*/, opNames); + + Qubit q1 = tr->AllocateQubit(); + tr->TraceSingleQubitOp(3, 1, q1); + tr->TraceSingleQubitOp(5, 1, q1); + tr->InjectGlobalBarrier(4, 2); + tr->TraceSingleQubitOp(3, 4, q1); + tr->TraceSingleQubitOp(2, 1, q1); + + const std::string fileName = "tracer-test.txt"; + std::ofstream out; + out.open(fileName); + tr->PrintLayerMetrics(out, "\t", false /*printZeroMetrics*/); + out.close(); + + std::ifstream in(fileName); + string line; + REQUIRE(in.is_open()); + std::string metrics(std::istreambuf_iterator{in}, {}); + in.close(); + + std::stringstream expected; + expected << "layer_id\tname\tY\tZ\t5" << std::endl; + expected << "0\t\t\t1\t" << std::endl; + expected << "1\t\t\t\t1" << std::endl; + expected << "2\tb\t\t\t" << std::endl; + expected << "4\t\t\t1\t" << std::endl; + expected << "8\t\t1\t\t" << std::endl; + + INFO(metrics); + CHECK(metrics == expected.str()); +} diff --git a/src/QirRuntime/test/unittests/driver.cpp b/src/Qir/Runtime/unittests/driver.cpp similarity index 97% rename from src/QirRuntime/test/unittests/driver.cpp rename to src/Qir/Runtime/unittests/driver.cpp index f8f43d73242..9795d69e2c7 100644 --- a/src/QirRuntime/test/unittests/driver.cpp +++ b/src/Qir/Runtime/unittests/driver.cpp @@ -1,8 +1,8 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file -#include "catch.hpp" - -// https://github.com/catchorg/Catch2/blob/master/docs/tutorial.md - +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file +#include "catch.hpp" + +// https://github.com/catchorg/Catch2/blob/master/docs/tutorial.md + diff --git a/src/Qir/Samples/CMakeLists.txt b/src/Qir/Samples/CMakeLists.txt new file mode 100644 index 00000000000..10a8a657b63 --- /dev/null +++ b/src/Qir/Samples/CMakeLists.txt @@ -0,0 +1,37 @@ +cmake_minimum_required(VERSION 3.10) + +message(INFO "*** build config: ${CMAKE_BUILD_TYPE}") + +# set the project name and version +project(qir-samples) + +# specify the C++ standard, compiler and other tools +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED True) + +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG") + +if(WIN32) + if(CMAKE_BUILD_TYPE STREQUAL "Debug") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_DLL -D_MT -Xclang --dependent-lib=msvcrtd") + else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_DLL -D_MT -Xclang --dependent-lib=msvcrt") + endif() +endif() + +# feel free to customize these flags for your local builds (don't check in) +set(CMAKE_VERBOSE_MAKEFILE ON) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-inline") + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/../Common/cmake") + +set(public_includes "${PROJECT_SOURCE_DIR}/../Runtime/public") +set(common_includes "${PROJECT_SOURCE_DIR}/../Common/Include") +set(test_includes "${PROJECT_SOURCE_DIR}/../Common/externals/catch2") + +set(runtime_lib_path "${PROJECT_SOURCE_DIR}/../Runtime/build/${CMAKE_BUILD_TYPE}/bin") + +include(qir_cmake_include) + +add_subdirectory(StandaloneInputReference) diff --git a/src/QirRuntime/samples/StandaloneInputReference/.clang-tidy b/src/Qir/Samples/StandaloneInputReference/.clang-tidy similarity index 100% rename from src/QirRuntime/samples/StandaloneInputReference/.clang-tidy rename to src/Qir/Samples/StandaloneInputReference/.clang-tidy diff --git a/src/QirRuntime/samples/StandaloneInputReference/CMakeLists.txt b/src/Qir/Samples/StandaloneInputReference/CMakeLists.txt similarity index 69% rename from src/QirRuntime/samples/StandaloneInputReference/CMakeLists.txt rename to src/Qir/Samples/StandaloneInputReference/CMakeLists.txt index fb694fa533b..081ebd87ca0 100644 --- a/src/QirRuntime/samples/StandaloneInputReference/CMakeLists.txt +++ b/src/Qir/Samples/StandaloneInputReference/CMakeLists.txt @@ -6,43 +6,38 @@ add_executable(qir-input-reference-standalone ) # This is where the generated QIR file is specified. -compile_from_qir(qir-standalone-input-reference qir_standalone_input_reference_target) +target_source_from_qir(qir-input-reference-standalone qsharp/qir/qir-standalone-input-reference.ll) target_link_libraries(qir-input-reference-standalone PUBLIC - ${QIR_UTILITY_LIB} # created by compile_from_qir - "-L${CMAKE_BINARY_DIR}/lib/QIR" + "-L${runtime_lib_path}" -lMicrosoft.Quantum.Qir.Runtime - "-L${CMAKE_BINARY_DIR}/lib/QSharpFoundation" -lMicrosoft.Quantum.Qir.QSharp.Foundation - "-L${CMAKE_BINARY_DIR}/lib/QSharpCore" -lMicrosoft.Quantum.Qir.QSharp.Core ) -set(standalone_includes "${PROJECT_SOURCE_DIR}/externals/CLI11") +set(standalone_includes "${PROJECT_SOURCE_DIR}/../Common/externals/CLI11") target_include_directories(qir-input-reference-standalone PUBLIC "${standalone_includes}" "${public_includes}" ) -add_dependencies(qir-input-reference-standalone qir_standalone_input_reference_target) - install(TARGETS qir-input-reference-standalone RUNTIME DESTINATION "${CMAKE_BINARY_DIR}/bin") include(CTest) add_test( NAME qir-input-reference-standalone - COMMAND qir-input-reference-standalone --int-value 1 --integer-array 1 2 3 4 5 --double-value 0.5 --double-array 0.1 0.2 0.3 0.4 0.5 --bool-value true --bool-array true TRUE false fALSe 1 --pauli-value PauliX --pauli-array PauliI paulix PAULIY PAulIZ --range-value 1 2 10 --range-array 1 2 10 5 5 50 10 1 20 --string-value ASampleString --result-value one --result-array one ONE true TRUE 1 zero ZERO false FALSE 0 + COMMAND qir-input-reference-standalone --int-value 1 --integer-array 1 2 3 4 5 --double-value 0.5 --double-array 0.1 0.2 0.3 0.4 0.5 --bool-value true --bool-array true TRUE false fALSe 1 --pauli-value PauliI --pauli-array PauliI paulix PAULIY PAulIZ --range-value 1 2 10 --range-array 1 2 10 5 5 50 10 1 20 --string-value ASampleString --result-value one --result-array one ONE 1 0 zero ZERO --string-array StringA StringB StringC ) # set the environment path for loading shared libs the tests are using if(DEFINED ENV{NATIVE_SIMULATOR}) set(TEST_DEPS1 $ENV{NATIVE_SIMULATOR}) else() - set(TEST_DEPS1 "${PROJECT_SOURCE_DIR}/../Simulation/native/build/${CMAKE_BUILD_TYPE}") + set(TEST_DEPS1 "${PROJECT_SOURCE_DIR}/../../Simulation/native/build/${CMAKE_BUILD_TYPE}") endif() -set(TEST_DEPS2 "${CMAKE_BINARY_DIR}/bin") +set(TEST_DEPS2 "${PROJECT_SOURCE_DIR}/../Runtime/build/${CMAKE_BUILD_TYPE}/bin") set_property(TEST qir-input-reference-standalone PROPERTY ENVIRONMENT "LD_LIBRARY_PATH=${TEST_DEPS1}:${TEST_DEPS2}:${LD_LIBRARY_PATH}" "PATH=${TEST_DEPS1}\;${TEST_DEPS2}\;${PATH}" diff --git a/src/QirRuntime/samples/StandaloneInputReference/qir-driver.cpp b/src/Qir/Samples/StandaloneInputReference/qir-driver.cpp similarity index 51% rename from src/QirRuntime/samples/StandaloneInputReference/qir-driver.cpp rename to src/Qir/Samples/StandaloneInputReference/qir-driver.cpp index ee1d07a7cde..d5a3e934f82 100644 --- a/src/QirRuntime/samples/StandaloneInputReference/qir-driver.cpp +++ b/src/Qir/Samples/StandaloneInputReference/qir-driver.cpp @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include // for memcpy #include #include #include @@ -10,30 +9,63 @@ #include "CLI11.hpp" -#include "CoreTypes.hpp" #include "QirContext.hpp" -#include "QirTypes.hpp" -#include "QirRuntimeApi_I.hpp" -#include "SimFactory.hpp" #include "QirRuntime.hpp" +#include "SimFactory.hpp" using namespace Microsoft::Quantum; using namespace std; +struct InteropArray +{ + int64_t Size; + void* Data; + + InteropArray(int64_t size, void* data) : + Size(size), + Data(data){} +}; + +using RangeTuple = tuple; +struct InteropRange +{ + int64_t Start; + int64_t Step; + int64_t End; + + InteropRange() : + Start(0), + Step(0), + End(0){} + + InteropRange(RangeTuple rangeTuple) : + Start(get<0>(rangeTuple)), + Step(get<1>(rangeTuple)), + End(get<2>(rangeTuple)){} +}; + // This is the function corresponding to the QIR entry-point. -extern "C" int64_t Quantum__StandaloneSupportedInputs__ExerciseInputs__body( // NOLINT +extern "C" void Quantum__StandaloneSupportedInputs__ExerciseInputs( // NOLINT int64_t intValue, + InteropArray* integerArray, double doubleValue, - Result resultValue, - QirString* stringValue); - -const char FalseAsChar = 0x0; -const char TrueAsChar = 0x1; + InteropArray* doubleArray, + char boolValue, + InteropArray* boolArray, + char pauliValue, + InteropArray* pauliArray, + InteropRange* rangeValue, + char resultValue, + InteropArray* resultArray, + const char* stringValue); + +const char InteropFalseAsChar = 0x0; +const char InteropTrueAsChar = 0x1; map BoolAsCharMap{ - {"0", FalseAsChar}, - {"false", FalseAsChar}, - {"1", TrueAsChar}, - {"true", TrueAsChar}}; + {"0", InteropFalseAsChar}, + {"false", InteropFalseAsChar}, + {"1", InteropTrueAsChar}, + {"true", InteropTrueAsChar}}; map PauliMap{ {"PauliI", PauliId::PauliId_I}, @@ -41,59 +73,58 @@ map PauliMap{ {"PauliY", PauliId::PauliId_Y}, {"PauliZ", PauliId::PauliId_Z}}; +const char InteropResultZeroAsChar = 0x0; +const char InteropResultOneAsChar = 0x1; map ResultAsCharMap{ - {"0", FalseAsChar}, - {"Zero", FalseAsChar}, - {"false", FalseAsChar}, - {"1", TrueAsChar}, - {"One", TrueAsChar}, - {"true", TrueAsChar}}; + {"0", InteropResultZeroAsChar}, + {"Zero", InteropResultZeroAsChar}, + {"1", InteropResultOneAsChar}, + {"One", InteropResultOneAsChar} +}; template -QirArray* CreateQirArray(T* dataBuffer, int64_t itemCount) +unique_ptr CreateInteropArray(vector& v) +{ + unique_ptr array(new InteropArray(v.size(), v.data())); + return array; +} + +unique_ptr CreateInteropRange(RangeTuple rangeTuple) { - int32_t typeSize = sizeof(T); // NOLINT - QirArray* qirArray = quantum__rt__array_create_1d(typeSize, itemCount); - memcpy(qirArray->buffer, dataBuffer, typeSize * itemCount); - return qirArray; + unique_ptr range(new InteropRange(rangeTuple)); + return range; } -template -unique_ptr TranslateVectorToBuffer(vectorsourceVector, function translationFunction) +template +void FreePointerVector(vector& v) { - unique_ptr buffer (new D[sourceVector.size()]); - for (int index = 0; index < sourceVector.size(); index++) + for (auto p : v) { - buffer[index] = translationFunction(sourceVector[index]); + delete p; } - - return buffer; } -using RangeTuple = tuple; -QirRange TranslateRangeTupleToQirRange(RangeTuple rangeTuple) +char TranslatePauliToChar(PauliId& pauli) { - QirRange qirRange = { - get<0>(rangeTuple), // Start - get<1>(rangeTuple), // Step - get<2>(rangeTuple) // End - }; + return static_cast(pauli); +} - return qirRange; +template +void TranslateVector(vector& sourceVector, vector& destinationVector, function translationFunction) +{ + destinationVector.resize(sourceVector.size()); + transform(sourceVector.begin(), sourceVector.end(), destinationVector.begin(), translationFunction); } -bool TranslateCharToBool(char boolAsChar) +InteropRange* TranslateRangeTupleToInteropRangePointer(RangeTuple& rangeTuple) { - return (boolAsChar != FalseAsChar); + InteropRange* range = new InteropRange(rangeTuple); + return range; } -// Result Zero and One are opaque types defined by the runtime. They are declared here and initialized before executing -// the simulation. -Result RuntimeResultZero = nullptr; -Result RuntimeResultOne = nullptr; -Result TranslateCharToResult(char resultAsChar) +const char* TranslateStringToCharBuffer(string& s) { - return resultAsChar == FalseAsChar ? RuntimeResultZero : RuntimeResultOne; + return s.c_str(); } int main(int argc, char* argv[]) @@ -103,20 +134,14 @@ int main(int argc, char* argv[]) // Initialize simulator. unique_ptr sim = CreateFullstateSimulator(); QirContextScope qirctx(sim.get(), false /*trackAllocatedObjects*/); - RuntimeResultZero = sim->UseZero(); - RuntimeResultOne = sim->UseOne(); - // Add the --simulation-output and --operation-output options. - // N.B. These options should be present in all standalone drivers. + // Add the --simulation-output options. + // N.B. This option should be present in all standalone drivers. string simulationOutputFile; CLI::Option* simulationOutputFileOpt = app.add_option( "-s,--simulation-output", simulationOutputFile, "File where the output produced during the simulation is written"); - string operationOutputFile; - CLI::Option* operationOutputFileOpt = app.add_option( - "-o,--operation-output", operationOutputFile, "File where the output of the Q# operation is written"); - // Add the options that correspond to the parameters that the QIR entry-point needs. // Option for a Q# Int type. int64_t intValue = 0; @@ -135,8 +160,10 @@ int main(int argc, char* argv[]) app.add_option("--double-array", doubleVector, "A double array")->required(); // Option for a Q# Bool type. - bool boolValue = false; - app.add_option("--bool-value", boolValue, "A bool value")->required(); + char boolAsCharValue = InteropFalseAsChar; + app.add_option("--bool-value", boolAsCharValue, "A bool value") + ->required() + ->transform(CLI::CheckedTransformer(BoolAsCharMap, CLI::ignore_case)); // Option for a Q# Array type. // N.B. For command line parsing, a char vector is used because vector is a specialized version of vector not @@ -161,8 +188,8 @@ int main(int argc, char* argv[]) // Option for Q# Range type. // N.B. RangeTuple type is used here instead of QirRange because CLI11 supports tuple parsing which is leveraged and // the tuple is later translated to QirRange. - RangeTuple rangeValue(0, 0, 0); - app.add_option("--range-value", rangeValue, "A Range value (start, step, end)")->required(); + RangeTuple rangeTuple(0, 0, 0); + app.add_option("--range-value", rangeTuple, "A Range value (start, step, end)")->required(); // Option for a Q# Array type. vector rangeTupleVector; @@ -171,7 +198,7 @@ int main(int argc, char* argv[]) // Option for Q# Result type. // N.B. This is implemented as a char rather than a boolean to be consistent with the way an array of results has to // be implemented. - char resultAsCharValue = FalseAsChar; + char resultAsCharValue = InteropResultZeroAsChar; app.add_option("--result-value", resultAsCharValue, "A Result value") ->required() ->transform(CLI::CheckedTransformer(ResultAsCharMap, CLI::ignore_case)); @@ -188,41 +215,45 @@ int main(int argc, char* argv[]) string stringValue; app.add_option("--string-value", stringValue, "A String value")->required(); + // Option for a Q# Array type. + vector stringVector; + app.add_option("--string-array", stringVector, "A String array")->required(); + + // With all the options added, parse arguments from the command line. CLI11_PARSE(app, argc, argv); // Translate values to its final form after parsing. - // Create a QirArray of integer values. - QirArray* qirIntegerArray = CreateQirArray(integerVector.data(), integerVector.size()); - - // Create a QirArray of double values. - QirArray* qirDoubleArray = CreateQirArray(doubleVector.data(), doubleVector.size()); - - // Create a QirArray of bool values. - unique_ptr boolArray = TranslateVectorToBuffer(boolAsCharVector, TranslateCharToBool); - QirArray* qirboolArray = CreateQirArray(boolArray.get(), boolAsCharVector.size()); + // Create an interop array of integer values. + unique_ptr integerArray = CreateInteropArray(integerVector); - // Create a QirArray of Pauli values. - QirArray* qirPauliArray = CreateQirArray(pauliVector.data(), pauliVector.size()); + // Create an interop array of double values. + unique_ptr doubleArray = CreateInteropArray(doubleVector); - // Create a QirRange. - QirRange qirRange = TranslateRangeTupleToQirRange(rangeValue); + // Create an interop array of bool values. + unique_ptr boolArray = CreateInteropArray(boolAsCharVector); - // Create a QirArray of Range values. - unique_ptr rangeArray = TranslateVectorToBuffer( - rangeTupleVector, TranslateRangeTupleToQirRange); + // Translate a PauliID value to its char representation. + char pauliAsCharValue = TranslatePauliToChar(pauliValue); - QirArray* qirRangeArray = CreateQirArray(rangeArray.get(), rangeTupleVector.size()); + // Create an interop array of Pauli values represented as chars. + vector pauliAsCharVector; + TranslateVector(pauliVector, pauliAsCharVector, TranslatePauliToChar); + unique_ptr pauliArray = CreateInteropArray(pauliAsCharVector); - // Create a Result. - Result result = TranslateCharToResult(resultAsCharValue); + // Create an interop range. + unique_ptr rangeValue = CreateInteropRange(rangeTuple); + vector rangeVector; + TranslateVector(rangeTupleVector, rangeVector, TranslateRangeTupleToInteropRangePointer); + unique_ptr rangeArray = CreateInteropArray(rangeVector); - // Create a QirArray of Result values. - unique_ptr resultArray = TranslateVectorToBuffer(resultAsCharVector, TranslateCharToResult); - QirArray* qirResultArray = CreateQirArray(resultArray.get(), resultAsCharVector.size()); + // Create an interop array of Result values. + unique_ptr resultArray = CreateInteropArray(resultAsCharVector); - // Create a QirString. - QirString* qirString = quantum__rt__string_create(stringValue.c_str()); + // Create an interop array of String values. + vector stringBufferVector; + TranslateVector(stringVector, stringBufferVector, TranslateStringToCharBuffer); + unique_ptr stringArray = CreateInteropArray(stringBufferVector); // Redirect the simulator output from std::cout if the --simulation-output option is present. ostream* simulatorOutputStream = &cout; @@ -234,29 +265,23 @@ int main(int argc, char* argv[]) simulatorOutputStream = &simulationOutputFileStream; } - // Redirect the Q# operation output from std::cout if the --operation-output option is present. - ostream* operationOutputStream = &cout; - ofstream operationOutputFileStream; - if (!operationOutputFileOpt->empty()) - { - operationOutputFileStream.open(operationOutputFile); - operationOutputStream = &operationOutputFileStream; - } - // Run simulation and write the output of the operation to the corresponding stream. - int64_t operationOutput = Quantum__StandaloneSupportedInputs__ExerciseInputs__body( - intValue, doubleValue, result, qirString); - + Quantum__StandaloneSupportedInputs__ExerciseInputs( + intValue, + integerArray.get(), + doubleValue, + doubleArray.get(), + boolAsCharValue, + boolArray.get(), + pauliAsCharValue, + pauliArray.get(), + rangeValue.get(), + resultAsCharValue, + resultArray.get(), + stringValue.c_str()); + + FreePointerVector(rangeVector); simulatorOutputStream->flush(); - (*operationOutputStream) << operationOutput << endl; - operationOutputStream->flush(); - - // Close opened file buffers; - if (operationOutputFileStream.is_open()) - { - operationOutputFileStream.close(); - } - if (simulationOutputFileStream.is_open()) { simulationOutputFileStream.close(); diff --git a/src/Qir/Samples/StandaloneInputReference/qsharp/qir-standalone-input-reference.csproj b/src/Qir/Samples/StandaloneInputReference/qsharp/qir-standalone-input-reference.csproj new file mode 100644 index 00000000000..9c141f761d3 --- /dev/null +++ b/src/Qir/Samples/StandaloneInputReference/qsharp/qir-standalone-input-reference.csproj @@ -0,0 +1,13 @@ + + + + Exe + netcoreapp3.1 + True + + + + + + + diff --git a/src/Qir/Samples/StandaloneInputReference/qsharp/qir-standalone-input-reference.qs b/src/Qir/Samples/StandaloneInputReference/qsharp/qir-standalone-input-reference.qs new file mode 100644 index 00000000000..23908eaa514 --- /dev/null +++ b/src/Qir/Samples/StandaloneInputReference/qsharp/qir-standalone-input-reference.qs @@ -0,0 +1,49 @@ +namespace Quantum.StandaloneSupportedInputs { + + open Microsoft.Quantum.Arrays; + open Microsoft.Quantum.Canon; + open Microsoft.Quantum.Intrinsic; + + function ArrayToString<'T> (array : 'T[]) : String + { + mutable first = true; + mutable itemsString = "["; + for item in array + { + if (first) + { + set first = false; + set itemsString = itemsString + $"{item}"; + } + else + { + set itemsString = itemsString + $", {item}"; + } + } + + set itemsString = itemsString + "]"; + return itemsString; + } + + function TautologyPredicate<'T> (input : 'T) : Bool + { + return true; + } + + @EntryPoint() + operation ExerciseInputs (intValue : Int, intArray : Int[], doubleValue : Double, doubleArray : Double[], boolValue : Bool, boolArray : Bool[], pauliValue : Pauli, pauliArray : Pauli[], rangeValue : Range, resultValue : Result, resultArray : Result[], stringValue : String) : Unit { + Message("Exercise Supported Inputs Reference"); + Message($"intValue: {intValue}"); + Message($"intArray: {ArrayToString(intArray)} ({Count(TautologyPredicate, intArray)})"); + Message($"doubleValue: {doubleValue}"); + Message($"doubleArray: {ArrayToString(doubleArray)} ({Count(TautologyPredicate, doubleArray)})"); + Message($"boolValue: {boolValue}"); + Message($"boolArray: {ArrayToString(boolArray)} ({Count(TautologyPredicate, boolArray)})"); + Message($"pauliValue: {pauliValue}"); + Message($"pauliArray: {ArrayToString(pauliArray)} ({Count(TautologyPredicate, pauliArray)})"); + Message($"rangeValue: {rangeValue}"); + Message($"resultValue: {resultValue}"); + Message($"resultArray: {ArrayToString(resultArray)} ({Count(TautologyPredicate, resultArray)})"); + Message($"stringValue: {stringValue}"); + } +} diff --git a/src/QirRuntime/samples/StandaloneInputReference/readme.md b/src/Qir/Samples/StandaloneInputReference/readme.md similarity index 100% rename from src/QirRuntime/samples/StandaloneInputReference/readme.md rename to src/Qir/Samples/StandaloneInputReference/readme.md diff --git a/src/Qir/Samples/build-qir-samples.ps1 b/src/Qir/Samples/build-qir-samples.ps1 new file mode 100644 index 00000000000..e56bc082786 --- /dev/null +++ b/src/Qir/Samples/build-qir-samples.ps1 @@ -0,0 +1,18 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +[CmdletBinding()] +param ( + [Parameter()] + [Switch] + $SkipQSharpBuild +) + +. (Join-Path $PSScriptRoot .. qir-utils.ps1) + +Write-Host "##[info]Compile Q# Projects into QIR" +Build-QirProject (Join-Path $PSScriptRoot StandaloneInputReference qsharp) -SkipQSharpBuild:$SkipQSharpBuild + +if (-not (Build-CMakeProject $PSScriptRoot "QIR Samples")) { + throw "At least one project failed to compile. Check the logs." +} \ No newline at end of file diff --git a/src/Qir/Samples/test-qir-samples.ps1 b/src/Qir/Samples/test-qir-samples.ps1 new file mode 100644 index 00000000000..f4825010c94 --- /dev/null +++ b/src/Qir/Samples/test-qir-samples.ps1 @@ -0,0 +1,8 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +. (Join-Path $PSScriptRoot .. qir-utils.ps1) + +if (-not (Test-CTest (Join-Path $PSScriptRoot build $Env:BUILD_CONFIGURATION StandaloneInputReference) "QIR Samples (StandaloneInputReference)")) { + throw "At least one project failed testing. Check the logs." +} diff --git a/src/Qir/Tests/CMakeLists.txt b/src/Qir/Tests/CMakeLists.txt new file mode 100644 index 00000000000..66fe8e15d8b --- /dev/null +++ b/src/Qir/Tests/CMakeLists.txt @@ -0,0 +1,41 @@ +cmake_minimum_required(VERSION 3.10) + +message(INFO "*** build config: ${CMAKE_BUILD_TYPE}") + +# set the project name and version +project(qir-tests) + +# specify the C++ standard, compiler and other tools +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED True) + +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG") + +if(WIN32) + if(CMAKE_BUILD_TYPE STREQUAL "Debug") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_DLL -D_MT -Xclang --dependent-lib=msvcrtd") + else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_DLL -D_MT -Xclang --dependent-lib=msvcrt") + endif() +endif() + +# feel free to customize these flags for your local builds (don't check in) +set(CMAKE_VERBOSE_MAKEFILE ON) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-inline") + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/../Common/cmake") + +set(public_includes "${PROJECT_SOURCE_DIR}/../Runtime/public") +set(common_includes "${PROJECT_SOURCE_DIR}/../Common/Include") +set(test_includes "${PROJECT_SOURCE_DIR}/../Common/externals/catch2") + +set(runtime_lib_path "${PROJECT_SOURCE_DIR}/../Runtime/build/${CMAKE_BUILD_TYPE}/bin") + +include(qir_cmake_include) +include(unit_test_include) + +add_subdirectory(FullstateSimulator) +add_subdirectory(QIR-dynamic) +add_subdirectory(QIR-static) +add_subdirectory(QIR-tracer) diff --git a/src/Qir/Tests/FullstateSimulator/CMakeLists.txt b/src/Qir/Tests/FullstateSimulator/CMakeLists.txt new file mode 100644 index 00000000000..8ff31f20eba --- /dev/null +++ b/src/Qir/Tests/FullstateSimulator/CMakeLists.txt @@ -0,0 +1,20 @@ +add_executable(fullstate-simulator-tests + FullstateSimulatorTests.cpp) + +target_source_from_qir(fullstate-simulator-tests qsharp/qir/qir-test-simulator.ll) + +target_link_libraries(fullstate-simulator-tests PUBLIC + "-L${runtime_lib_path}" + -lMicrosoft.Quantum.Qir.Runtime + -lMicrosoft.Quantum.Qir.QSharp.Foundation + -lMicrosoft.Quantum.Qir.QSharp.Core +) + +target_include_directories(fullstate-simulator-tests PUBLIC + ${test_includes} + ${public_includes} +) + +install(TARGETS fullstate-simulator-tests RUNTIME DESTINATION "${CMAKE_BINARY_DIR}/bin") +add_unit_test(fullstate-simulator-tests) + diff --git a/src/QirRuntime/test/FullstateSimulator/FullstateSimulatorTests.cpp b/src/Qir/Tests/FullstateSimulator/FullstateSimulatorTests.cpp similarity index 96% rename from src/QirRuntime/test/FullstateSimulator/FullstateSimulatorTests.cpp rename to src/Qir/Tests/FullstateSimulator/FullstateSimulatorTests.cpp index 2e9bc0fb351..39a168f2ccc 100644 --- a/src/QirRuntime/test/FullstateSimulator/FullstateSimulatorTests.cpp +++ b/src/Qir/Tests/FullstateSimulator/FullstateSimulatorTests.cpp @@ -1,363 +1,363 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include -#include -#include - -#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file -#include "catch.hpp" - -#include "QirRuntimeApi_I.hpp" -#include "QSharpSimApi_I.hpp" -#include "SimFactory.hpp" -#include "QirContext.hpp" - -using namespace Microsoft::Quantum; -using namespace std; - -// The tests rely on the implementation detail of CFullstateSimulator that the qubits are nothing more but contiguously -// incremented ids. -unsigned GetQubitId(Qubit q) -{ - return static_cast(reinterpret_cast(q)); -} - -static Result MZ(IQuantumGateSet* iqa, Qubit q) -{ - PauliId pauliZ[1] = {PauliId_Z}; - Qubit qs[1] = {q}; - return iqa->Measure(1, pauliZ, 1, qs); -} - -TEST_CASE("Fullstate simulator: allocate qubits", "[fullstate_simulator]") -{ - std::unique_ptr sim = CreateFullstateSimulator(); - - Qubit q0 = sim->AllocateQubit(); - Qubit q1 = sim->AllocateQubit(); - REQUIRE(GetQubitId(q0) == 0); - REQUIRE(GetQubitId(q1) == 1); - sim->ReleaseQubit(q0); - sim->ReleaseQubit(q1); -} - -TEST_CASE("Fullstate simulator: multiple instances", "[fullstate_simulator]") -{ - std::unique_ptr sim1 = CreateFullstateSimulator(); - Qubit q1 = sim1->AllocateQubit(); - - std::unique_ptr sim2 = CreateFullstateSimulator(); - Qubit q2 = sim2->AllocateQubit(); - - REQUIRE(GetQubitId(q1) == 0); - REQUIRE(GetQubitId(q2) == 0); - - sim1->ReleaseQubit(q1); - sim2->ReleaseQubit(q2); -} - -TEST_CASE("Fullstate simulator: X and measure", "[fullstate_simulator]") -{ - std::unique_ptr sim = CreateFullstateSimulator(); - IQuantumGateSet* iqa = dynamic_cast(sim.get()); - - Qubit q = sim->AllocateQubit(); - Result r1 = MZ(iqa, q); - REQUIRE(Result_Zero == sim->GetResultValue(r1)); - REQUIRE(sim->AreEqualResults(r1, sim->UseZero())); - - iqa->X(q); - Result r2 = MZ(iqa, q); - REQUIRE(Result_One == sim->GetResultValue(r2)); - REQUIRE(sim->AreEqualResults(r2, sim->UseOne())); - - sim->ReleaseQubit(q); - sim->ReleaseResult(r1); - sim->ReleaseResult(r2); -} - -TEST_CASE("Fullstate simulator: measure Bell state", "[fullstate_simulator]") -{ - std::unique_ptr sim = CreateFullstateSimulator(); - IQuantumGateSet* iqa = dynamic_cast(sim.get()); - - Qubit q1 = sim->AllocateQubit(); - Qubit q2 = sim->AllocateQubit(); - - iqa->H(q1); - iqa->ControlledX(1, &q1, q2); - - Result r1 = MZ(iqa, q1); - Result r2 = MZ(iqa, q2); - REQUIRE(sim->AreEqualResults(r1, r2)); - - sim->ReleaseQubit(q1); - sim->ReleaseQubit(q2); -} - -TEST_CASE("Fullstate simulator: ZZ measure", "[fullstate_simulator]") -{ - std::unique_ptr sim = CreateFullstateSimulator(); - IQuantumGateSet* iqa = dynamic_cast(sim.get()); - - Qubit q[2]; - PauliId paulis[2] = {PauliId_Z, PauliId_Z}; - - q[0] = sim->AllocateQubit(); - q[1] = sim->AllocateQubit(); - iqa->H(q[0]); - iqa->ControlledX(1, &q[0], q[1]); - Result rZero = iqa->Measure(2, paulis, 2, q); - REQUIRE(Result_Zero == sim->GetResultValue(rZero)); - - iqa->X(q[1]); - Result rOne = iqa->Measure(2, paulis, 2, q); - REQUIRE(Result_One == sim->GetResultValue(rOne)); - - sim->ReleaseQubit(q[0]); - sim->ReleaseQubit(q[1]); -} - -TEST_CASE("Fullstate simulator: assert probability", "[fullstate_simulator]") -{ - std::unique_ptr sim = CreateFullstateSimulator(); - IQuantumGateSet* iqa = dynamic_cast(sim.get()); - - Qubit qs[2]; - qs[0] = sim->AllocateQubit(); - qs[1] = sim->AllocateQubit(); - iqa->X(qs[0]); - - PauliId zz[2] = {PauliId_Z, PauliId_Z}; - PauliId iz[2] = {PauliId_I, PauliId_Z}; - PauliId xi[2] = {PauliId_X, PauliId_I}; - - IDiagnostics* idig = dynamic_cast(sim.get()); - REQUIRE(idig->AssertProbability(2, zz, qs, 0.0, 1e-10, "")); - REQUIRE(idig->AssertProbability(2, iz, qs, 1.0, 1e-10, "")); - REQUIRE(idig->AssertProbability(2, xi, qs, 0.5, 1e-10, "")); - - REQUIRE(idig->Assert(2, zz, qs, sim->UseOne(), "")); - REQUIRE(idig->Assert(2, iz, qs, sim->UseZero(), "")); - REQUIRE(!idig->Assert(2, xi, qs, sim->UseZero(), "")); - REQUIRE(!idig->Assert(2, xi, qs, sim->UseOne(), "")); - - sim->ReleaseQubit(qs[0]); - sim->ReleaseQubit(qs[1]); -} - -TEST_CASE("Fullstate simulator: toffoli", "[fullstate_simulator]") -{ - std::unique_ptr sim = CreateFullstateSimulator(); - IQuantumGateSet* iqa = dynamic_cast(sim.get()); - - Qubit qs[3]; - for (int i = 0; i < 3; i++) - { - qs[i] = sim->AllocateQubit(); - } - - iqa->X(qs[0]); - iqa->ControlledX(2, qs, qs[2]); - REQUIRE(Result_Zero == sim->GetResultValue(MZ(iqa, qs[2]))); - - iqa->X(qs[1]); - iqa->ControlledX(2, qs, qs[2]); - REQUIRE(Result_One == sim->GetResultValue(MZ(iqa, qs[2]))); - - for (int i = 0; i < 3; i++) - { - sim->ReleaseQubit(qs[i]); - } -} - -TEST_CASE("Fullstate simulator: SSZ=Id", "[fullstate_simulator]") -{ - std::unique_ptr sim = CreateFullstateSimulator(); - IQuantumGateSet* iqa = dynamic_cast(sim.get()); - - Qubit q = sim->AllocateQubit(); - - bool identitySSZ = true; - for (int i = 0; i < 100 && identitySSZ; i++) - { - iqa->H(q); - iqa->S(q); - iqa->S(q); - iqa->Z(q); - iqa->H(q); - identitySSZ = (Result_Zero == sim->GetResultValue(MZ(iqa, q))); - } - REQUIRE(identitySSZ); - - sim->ReleaseQubit(q); -} - -TEST_CASE("Fullstate simulator: TTSAdj=Id", "[fullstate_simulator]") -{ - std::unique_ptr sim = CreateFullstateSimulator(); - IQuantumGateSet* iqa = dynamic_cast(sim.get()); - - Qubit q = sim->AllocateQubit(); - - bool identityTTSAdj = true; - for (int i = 0; i < 100 && identityTTSAdj; i++) - { - iqa->H(q); - iqa->T(q); - iqa->T(q); - iqa->AdjointS(q); - iqa->H(q); - identityTTSAdj = (Result_Zero == sim->GetResultValue(MZ(iqa, q))); - } - REQUIRE(identityTTSAdj); - - sim->ReleaseQubit(q); -} - -TEST_CASE("Fullstate simulator: TTAdj=Id", "[fullstate_simulator]") -{ - std::unique_ptr sim = CreateFullstateSimulator(); - IQuantumGateSet* iqa = dynamic_cast(sim.get()); - - Qubit q = sim->AllocateQubit(); - - bool identityTTadj = true; - for (int i = 0; i < 100 && identityTTadj; i++) - { - iqa->H(q); - iqa->T(q); - iqa->AdjointT(q); - iqa->H(q); - identityTTadj = (Result_Zero == sim->GetResultValue(MZ(iqa, q))); - } - REQUIRE(identityTTadj); - - sim->ReleaseQubit(q); -} - -TEST_CASE("Fullstate simulator: R", "[fullstate_simulator]") -{ - constexpr double pi = 3.1415926535897932384626433832795028841971693993751058209749445923078164062; - std::unique_ptr sim = CreateFullstateSimulator(); - IQuantumGateSet* iqa = dynamic_cast(sim.get()); - - Qubit q = sim->AllocateQubit(); - bool identity = true; - for (int i = 0; i < 100 && identity; i++) - { - iqa->H(q); - iqa->R(PauliId_X, q, 0.42); - iqa->R(PauliId_Y, q, 0.17); - iqa->T(q); - iqa->R(PauliId_Z, q, -pi / 4.0); - iqa->R(PauliId_Y, q, -0.17); - iqa->R(PauliId_X, q, -0.42); - iqa->H(q); - identity = (Result_Zero == sim->GetResultValue(MZ(iqa, q))); - } - REQUIRE(identity); - - sim->ReleaseQubit(q); -} - -TEST_CASE("Fullstate simulator: exponents", "[fullstate_simulator]") -{ - std::unique_ptr sim = CreateFullstateSimulator(); - IQuantumGateSet* iqa = dynamic_cast(sim.get()); - const int n = 5; - - Qubit qs[n]; - for (int i = 0; i < n; i++) - { - qs[i] = sim->AllocateQubit(); - } - - PauliId paulis[3] = {PauliId_X, PauliId_Y, PauliId_Z}; - iqa->Exp(2, paulis, qs, 0.42); - iqa->ControlledExp(2, qs, 3, paulis, &qs[2], 0.17); - - // not crashes? consider it passing - REQUIRE(true); - - for (int i = 0; i < n; i++) - { - sim->ReleaseQubit(qs[i]); - } -} - -TEST_CASE("Fullstate simulator: get qubit state of Bell state", "[fullstate_simulator]") -{ - std::unique_ptr sim = CreateFullstateSimulator(); - IQuantumGateSet* iqa = dynamic_cast(sim.get()); - - const int n = 3; - static double norm = 0.0; - - Qubit qs[n]; - for (int i = 0; i < n; i++) - { - qs[i] = sim->AllocateQubit(); - } - - iqa->H(qs[0]); - iqa->ControlledX(1, &qs[0], qs[1]); - // 1/sqrt(2)(|00> + |11>)x|0> - - dynamic_cast(sim.get())->GetState([](size_t idx, double re, double im) { - norm += re * re + im * im; - REQUIRE(idx < 4); - switch (idx) - { - case 0: - case 3: - REQUIRE((1 / sqrt(2.0) == Approx(re).epsilon(0.0001))); - REQUIRE(im == 0.0); - break; - default: - REQUIRE(re == 0.0); - REQUIRE(im == 0.0); - break; - } - return idx < 3; // the last qubit is in separable |0> state - }); - REQUIRE(1.0 == Approx(norm).epsilon(0.0001)); - norm = 0.0; - - iqa->Y(qs[2]); - // 1/sqrt(2)(|00> + |11>)xi|1> - - dynamic_cast(sim.get())->GetState([](size_t idx, double re, double im) { - norm += re * re + im * im; - switch (idx) - { - case 4: - case 7: - REQUIRE(re == 0.0); - REQUIRE(1 / sqrt(2.0) == Approx(im).epsilon(0.0001)); - break; - default: - REQUIRE(re == 0.0); - REQUIRE(im == 0.0); - break; - } - return true; // get full state - }); - REQUIRE(1.0 == Approx(norm).epsilon(0.0001)); - norm = 0.0; - - for (int i = 0; i < n; i++) - { - sim->ReleaseQubit(qs[i]); - } -} - -extern "C" int Microsoft__Quantum__Testing__QIR__Test_Simulator_QIS__body(); // NOLINT -TEST_CASE("QIR: invoke all standard Q# gates against the fullstate simulator", "[fullstate_simulator]") -{ - std::unique_ptr sim = CreateFullstateSimulator(); - QirContextScope qirctx(sim.get(), true /*trackAllocatedObjects*/); - - REQUIRE(0 == Microsoft__Quantum__Testing__QIR__Test_Simulator_QIS__body()); +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include +#include +#include + +#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file +#include "catch.hpp" + +#include "QirRuntimeApi_I.hpp" +#include "QSharpSimApi_I.hpp" +#include "SimFactory.hpp" +#include "QirContext.hpp" + +using namespace Microsoft::Quantum; +using namespace std; + +// The tests rely on the implementation detail of CFullstateSimulator that the qubits are nothing more but contiguously +// incremented ids. +unsigned GetQubitId(Qubit q) +{ + return static_cast(reinterpret_cast(q)); +} + +static Result MZ(IQuantumGateSet* iqa, Qubit q) +{ + PauliId pauliZ[1] = {PauliId_Z}; + Qubit qs[1] = {q}; + return iqa->Measure(1, pauliZ, 1, qs); +} + +TEST_CASE("Fullstate simulator: allocate qubits", "[fullstate_simulator]") +{ + std::unique_ptr sim = CreateFullstateSimulator(); + + Qubit q0 = sim->AllocateQubit(); + Qubit q1 = sim->AllocateQubit(); + REQUIRE(GetQubitId(q0) == 0); + REQUIRE(GetQubitId(q1) == 1); + sim->ReleaseQubit(q0); + sim->ReleaseQubit(q1); +} + +TEST_CASE("Fullstate simulator: multiple instances", "[fullstate_simulator]") +{ + std::unique_ptr sim1 = CreateFullstateSimulator(); + Qubit q1 = sim1->AllocateQubit(); + + std::unique_ptr sim2 = CreateFullstateSimulator(); + Qubit q2 = sim2->AllocateQubit(); + + REQUIRE(GetQubitId(q1) == 0); + REQUIRE(GetQubitId(q2) == 0); + + sim1->ReleaseQubit(q1); + sim2->ReleaseQubit(q2); +} + +TEST_CASE("Fullstate simulator: X and measure", "[fullstate_simulator]") +{ + std::unique_ptr sim = CreateFullstateSimulator(); + IQuantumGateSet* iqa = dynamic_cast(sim.get()); + + Qubit q = sim->AllocateQubit(); + Result r1 = MZ(iqa, q); + REQUIRE(Result_Zero == sim->GetResultValue(r1)); + REQUIRE(sim->AreEqualResults(r1, sim->UseZero())); + + iqa->X(q); + Result r2 = MZ(iqa, q); + REQUIRE(Result_One == sim->GetResultValue(r2)); + REQUIRE(sim->AreEqualResults(r2, sim->UseOne())); + + sim->ReleaseQubit(q); + sim->ReleaseResult(r1); + sim->ReleaseResult(r2); +} + +TEST_CASE("Fullstate simulator: measure Bell state", "[fullstate_simulator]") +{ + std::unique_ptr sim = CreateFullstateSimulator(); + IQuantumGateSet* iqa = dynamic_cast(sim.get()); + + Qubit q1 = sim->AllocateQubit(); + Qubit q2 = sim->AllocateQubit(); + + iqa->H(q1); + iqa->ControlledX(1, &q1, q2); + + Result r1 = MZ(iqa, q1); + Result r2 = MZ(iqa, q2); + REQUIRE(sim->AreEqualResults(r1, r2)); + + sim->ReleaseQubit(q1); + sim->ReleaseQubit(q2); +} + +TEST_CASE("Fullstate simulator: ZZ measure", "[fullstate_simulator]") +{ + std::unique_ptr sim = CreateFullstateSimulator(); + IQuantumGateSet* iqa = dynamic_cast(sim.get()); + + Qubit q[2]; + PauliId paulis[2] = {PauliId_Z, PauliId_Z}; + + q[0] = sim->AllocateQubit(); + q[1] = sim->AllocateQubit(); + iqa->H(q[0]); + iqa->ControlledX(1, &q[0], q[1]); + Result rZero = iqa->Measure(2, paulis, 2, q); + REQUIRE(Result_Zero == sim->GetResultValue(rZero)); + + iqa->X(q[1]); + Result rOne = iqa->Measure(2, paulis, 2, q); + REQUIRE(Result_One == sim->GetResultValue(rOne)); + + sim->ReleaseQubit(q[0]); + sim->ReleaseQubit(q[1]); +} + +TEST_CASE("Fullstate simulator: assert probability", "[fullstate_simulator]") +{ + std::unique_ptr sim = CreateFullstateSimulator(); + IQuantumGateSet* iqa = dynamic_cast(sim.get()); + + Qubit qs[2]; + qs[0] = sim->AllocateQubit(); + qs[1] = sim->AllocateQubit(); + iqa->X(qs[0]); + + PauliId zz[2] = {PauliId_Z, PauliId_Z}; + PauliId iz[2] = {PauliId_I, PauliId_Z}; + PauliId xi[2] = {PauliId_X, PauliId_I}; + + IDiagnostics* idig = dynamic_cast(sim.get()); + REQUIRE(idig->AssertProbability(2, zz, qs, 0.0, 1e-10, "")); + REQUIRE(idig->AssertProbability(2, iz, qs, 1.0, 1e-10, "")); + REQUIRE(idig->AssertProbability(2, xi, qs, 0.5, 1e-10, "")); + + REQUIRE(idig->Assert(2, zz, qs, sim->UseOne(), "")); + REQUIRE(idig->Assert(2, iz, qs, sim->UseZero(), "")); + REQUIRE(!idig->Assert(2, xi, qs, sim->UseZero(), "")); + REQUIRE(!idig->Assert(2, xi, qs, sim->UseOne(), "")); + + sim->ReleaseQubit(qs[0]); + sim->ReleaseQubit(qs[1]); +} + +TEST_CASE("Fullstate simulator: toffoli", "[fullstate_simulator]") +{ + std::unique_ptr sim = CreateFullstateSimulator(); + IQuantumGateSet* iqa = dynamic_cast(sim.get()); + + Qubit qs[3]; + for (int i = 0; i < 3; i++) + { + qs[i] = sim->AllocateQubit(); + } + + iqa->X(qs[0]); + iqa->ControlledX(2, qs, qs[2]); + REQUIRE(Result_Zero == sim->GetResultValue(MZ(iqa, qs[2]))); + + iqa->X(qs[1]); + iqa->ControlledX(2, qs, qs[2]); + REQUIRE(Result_One == sim->GetResultValue(MZ(iqa, qs[2]))); + + for (int i = 0; i < 3; i++) + { + sim->ReleaseQubit(qs[i]); + } +} + +TEST_CASE("Fullstate simulator: SSZ=Id", "[fullstate_simulator]") +{ + std::unique_ptr sim = CreateFullstateSimulator(); + IQuantumGateSet* iqa = dynamic_cast(sim.get()); + + Qubit q = sim->AllocateQubit(); + + bool identitySSZ = true; + for (int i = 0; i < 100 && identitySSZ; i++) + { + iqa->H(q); + iqa->S(q); + iqa->S(q); + iqa->Z(q); + iqa->H(q); + identitySSZ = (Result_Zero == sim->GetResultValue(MZ(iqa, q))); + } + REQUIRE(identitySSZ); + + sim->ReleaseQubit(q); +} + +TEST_CASE("Fullstate simulator: TTSAdj=Id", "[fullstate_simulator]") +{ + std::unique_ptr sim = CreateFullstateSimulator(); + IQuantumGateSet* iqa = dynamic_cast(sim.get()); + + Qubit q = sim->AllocateQubit(); + + bool identityTTSAdj = true; + for (int i = 0; i < 100 && identityTTSAdj; i++) + { + iqa->H(q); + iqa->T(q); + iqa->T(q); + iqa->AdjointS(q); + iqa->H(q); + identityTTSAdj = (Result_Zero == sim->GetResultValue(MZ(iqa, q))); + } + REQUIRE(identityTTSAdj); + + sim->ReleaseQubit(q); +} + +TEST_CASE("Fullstate simulator: TTAdj=Id", "[fullstate_simulator]") +{ + std::unique_ptr sim = CreateFullstateSimulator(); + IQuantumGateSet* iqa = dynamic_cast(sim.get()); + + Qubit q = sim->AllocateQubit(); + + bool identityTTadj = true; + for (int i = 0; i < 100 && identityTTadj; i++) + { + iqa->H(q); + iqa->T(q); + iqa->AdjointT(q); + iqa->H(q); + identityTTadj = (Result_Zero == sim->GetResultValue(MZ(iqa, q))); + } + REQUIRE(identityTTadj); + + sim->ReleaseQubit(q); +} + +TEST_CASE("Fullstate simulator: R", "[fullstate_simulator]") +{ + constexpr double pi = 3.1415926535897932384626433832795028841971693993751058209749445923078164062; + std::unique_ptr sim = CreateFullstateSimulator(); + IQuantumGateSet* iqa = dynamic_cast(sim.get()); + + Qubit q = sim->AllocateQubit(); + bool identity = true; + for (int i = 0; i < 100 && identity; i++) + { + iqa->H(q); + iqa->R(PauliId_X, q, 0.42); + iqa->R(PauliId_Y, q, 0.17); + iqa->T(q); + iqa->R(PauliId_Z, q, -pi / 4.0); + iqa->R(PauliId_Y, q, -0.17); + iqa->R(PauliId_X, q, -0.42); + iqa->H(q); + identity = (Result_Zero == sim->GetResultValue(MZ(iqa, q))); + } + REQUIRE(identity); + + sim->ReleaseQubit(q); +} + +TEST_CASE("Fullstate simulator: exponents", "[fullstate_simulator]") +{ + std::unique_ptr sim = CreateFullstateSimulator(); + IQuantumGateSet* iqa = dynamic_cast(sim.get()); + const int n = 5; + + Qubit qs[n]; + for (int i = 0; i < n; i++) + { + qs[i] = sim->AllocateQubit(); + } + + PauliId paulis[3] = {PauliId_X, PauliId_Y, PauliId_Z}; + iqa->Exp(2, paulis, qs, 0.42); + iqa->ControlledExp(2, qs, 3, paulis, &qs[2], 0.17); + + // not crashes? consider it passing + REQUIRE(true); + + for (int i = 0; i < n; i++) + { + sim->ReleaseQubit(qs[i]); + } +} + +TEST_CASE("Fullstate simulator: get qubit state of Bell state", "[fullstate_simulator]") +{ + std::unique_ptr sim = CreateFullstateSimulator(); + IQuantumGateSet* iqa = dynamic_cast(sim.get()); + + const int n = 3; + static double norm = 0.0; + + Qubit qs[n]; + for (int i = 0; i < n; i++) + { + qs[i] = sim->AllocateQubit(); + } + + iqa->H(qs[0]); + iqa->ControlledX(1, &qs[0], qs[1]); + // 1/sqrt(2)(|00> + |11>)x|0> + + dynamic_cast(sim.get())->GetState([](size_t idx, double re, double im) { + norm += re * re + im * im; + REQUIRE(idx < 4); + switch (idx) + { + case 0: + case 3: + REQUIRE((1 / sqrt(2.0) == Approx(re).epsilon(0.0001))); + REQUIRE(im == 0.0); + break; + default: + REQUIRE(re == 0.0); + REQUIRE(im == 0.0); + break; + } + return idx < 3; // the last qubit is in separable |0> state + }); + REQUIRE(1.0 == Approx(norm).epsilon(0.0001)); + norm = 0.0; + + iqa->Y(qs[2]); + // 1/sqrt(2)(|00> + |11>)xi|1> + + dynamic_cast(sim.get())->GetState([](size_t idx, double re, double im) { + norm += re * re + im * im; + switch (idx) + { + case 4: + case 7: + REQUIRE(re == 0.0); + REQUIRE(1 / sqrt(2.0) == Approx(im).epsilon(0.0001)); + break; + default: + REQUIRE(re == 0.0); + REQUIRE(im == 0.0); + break; + } + return true; // get full state + }); + REQUIRE(1.0 == Approx(norm).epsilon(0.0001)); + norm = 0.0; + + for (int i = 0; i < n; i++) + { + sim->ReleaseQubit(qs[i]); + } +} + +extern "C" int Microsoft__Quantum__Testing__QIR__Test_Simulator_QIS__body(); // NOLINT +TEST_CASE("QIR: invoke all standard Q# gates against the fullstate simulator", "[fullstate_simulator]") +{ + std::unique_ptr sim = CreateFullstateSimulator(); + QirContextScope qirctx(sim.get(), true /*trackAllocatedObjects*/); + + REQUIRE(0 == Microsoft__Quantum__Testing__QIR__Test_Simulator_QIS__body()); } \ No newline at end of file diff --git a/src/Qir/Tests/FullstateSimulator/qsharp/qir-test-simulator.csproj b/src/Qir/Tests/FullstateSimulator/qsharp/qir-test-simulator.csproj new file mode 100644 index 00000000000..95dacab3142 --- /dev/null +++ b/src/Qir/Tests/FullstateSimulator/qsharp/qir-test-simulator.csproj @@ -0,0 +1,14 @@ + + + + Exe + netcoreapp3.1 + True + false + + + + + + + diff --git a/src/QirRuntime/test/FullstateSimulator/qir-test-simulator.qs b/src/Qir/Tests/FullstateSimulator/qsharp/qir-test-simulator.qs similarity index 67% rename from src/QirRuntime/test/FullstateSimulator/qir-test-simulator.qs rename to src/Qir/Tests/FullstateSimulator/qsharp/qir-test-simulator.qs index b32c6bed364..bb97857e50c 100644 --- a/src/QirRuntime/test/FullstateSimulator/qir-test-simulator.qs +++ b/src/Qir/Tests/FullstateSimulator/qsharp/qir-test-simulator.qs @@ -10,20 +10,23 @@ namespace Microsoft.Quantum.Testing.QIR operation InvokeAllVariants(op : (Qubit => Unit is Adj + Ctl)) : Int { mutable res = 0; - using((target, ctls) = (Qubit(), Qubit[2])) + use (target, ctls) = (Qubit(), Qubit[2]) { op(target); Adjoint op(target); - if (M(target) != Zero) { let res = 1; } + if (M(target) != Zero) { set res = 1; } else { H(ctls[0]); H(ctls[1]); Controlled op(ctls, target); Adjoint Controlled op(ctls, target); - if (M(target) != Zero) { return 2; } - H(ctls[0]); - H(ctls[1]); + if (M(target) != Zero) { set res = 2; } + else + { + H(ctls[0]); + H(ctls[1]); + } } } return res; @@ -33,33 +36,33 @@ namespace Microsoft.Quantum.Testing.QIR operation Test_Simulator_QIS() : Int { mutable res = 0; - let res = InvokeAllVariants(X); + set res = InvokeAllVariants(X); if (res != 0) { return res; } - let res = InvokeAllVariants(Y); + set res = InvokeAllVariants(Y); if (res != 0) { return 10 + res; } - let res = InvokeAllVariants(Z); + set res = InvokeAllVariants(Z); if (res != 0) { return 20 + res; } - let res = InvokeAllVariants(H); + set res = InvokeAllVariants(H); if (res != 0) { return 30 + res; } - let res = InvokeAllVariants(S); + set res = InvokeAllVariants(S); if (res != 0) { return 40 + res; } - let res = InvokeAllVariants(T); + set res = InvokeAllVariants(T); if (res != 0) { return 50 + res; } - let res = InvokeAllVariants(R(PauliX, 0.42, _)); + set res = InvokeAllVariants(R(PauliX, 0.42, _)); if (res != 0) { return 60 + res; } - using((targets, ctls) = (Qubit[2], Qubit[2])) + use (targets, ctls) = (Qubit[2], Qubit[2]) { let theta = 0.42; Exp([PauliX, PauliY], theta, targets); Adjoint Exp([PauliX, PauliY], theta, targets); - if (M(target) != Zero) { let res = 1; } + if (M(targets[0]) != Zero) { set res = 1; } H(ctls[0]); H(ctls[1]); @@ -67,15 +70,15 @@ namespace Microsoft.Quantum.Testing.QIR Adjoint Controlled Exp(ctls, ([PauliX, PauliY], theta, targets)); H(ctls[0]); H(ctls[1]); - if (M(target) != Zero) { let res = 70 + 2; } + if (M(targets[0]) != Zero) { set res = 2; } } if (res != 0) { return 70 + res; } - using (qs = Qubit[3]) + use qs = Qubit[3] { H(qs[0]); H(qs[2]); - if (Measure([PauliX, PauliZ, PauliX], qs) != zero) { let res = 80; } + if (Measure([PauliX, PauliZ, PauliX], qs) != Zero) { set res = 80; } } return res; } diff --git a/src/QirRuntime/test/QIR-dynamic/CMakeLists.txt b/src/Qir/Tests/QIR-dynamic/CMakeLists.txt similarity index 58% rename from src/QirRuntime/test/QIR-dynamic/CMakeLists.txt rename to src/Qir/Tests/QIR-dynamic/CMakeLists.txt index d40bcbd8871..a0b8a6f9dc2 100644 --- a/src/QirRuntime/test/QIR-dynamic/CMakeLists.txt +++ b/src/Qir/Tests/QIR-dynamic/CMakeLists.txt @@ -1,43 +1,30 @@ -if (WIN32) - set(TEST_FILES - qir-test-random-win - ) -else() - set(TEST_FILES - qir-test-random-lnx - ) -endif() - -foreach(file ${TEST_FILES}) - compile_from_qir(${file} "") # don't create a target per file - list(APPEND QIR_TESTS_LIBS ${QIR_UTILITY_LIB}) -endforeach() - -add_custom_target(qir_dynamic_test_lib DEPENDS ${QIR_TESTS_LIBS}) - -#============================================================================== -# This executable target links test code against the dynamic libraries rather than the explicit -# static QIR/RT libs (qir will statically link in the bridge via transitivity of target_link_libraries). -# -add_executable(qir-dynamic-tests - qir-driver.cpp -) - -target_link_libraries(qir-dynamic-tests PUBLIC - ${QIR_TESTS_LIBS} - "-L${CMAKE_BINARY_DIR}/lib/QIR" - -lMicrosoft.Quantum.Qir.Runtime - "-L${CMAKE_BINARY_DIR}/lib/QSharpFoundation" - -lMicrosoft.Quantum.Qir.QSharp.Foundation - "-L${CMAKE_BINARY_DIR}/lib/QSharpCore" - -lMicrosoft.Quantum.Qir.QSharp.Core -) - -target_include_directories(qir-dynamic-tests PUBLIC - ${test_includes} - ${public_includes} -) -add_dependencies(qir-dynamic-tests qir_dynamic_test_lib) - -install(TARGETS qir-dynamic-tests RUNTIME DESTINATION "${CMAKE_BINARY_DIR}/bin") -add_unit_test(qir-dynamic-tests) +set(TEST_FILES + qsharp/qir/qir-test-random.ll +) + +#============================================================================== +# This executable target links test code against the dynamic libraries rather than the explicit +# static QIR/RT libs (qir will statically link in the bridge via transitivity of target_link_libraries). +# +add_executable(qir-dynamic-tests + qir-driver.cpp +) + +foreach(file ${TEST_FILES}) + target_source_from_qir(qir-dynamic-tests ${file}) +endforeach() + +target_link_libraries(qir-dynamic-tests PUBLIC + "-L${runtime_lib_path}" + -lMicrosoft.Quantum.Qir.Runtime + -lMicrosoft.Quantum.Qir.QSharp.Foundation + -lMicrosoft.Quantum.Qir.QSharp.Core +) + +target_include_directories(qir-dynamic-tests PUBLIC + ${test_includes} + ${public_includes} +) + +install(TARGETS qir-dynamic-tests RUNTIME DESTINATION "${CMAKE_BINARY_DIR}/bin") +add_unit_test(qir-dynamic-tests) diff --git a/src/QirRuntime/test/QIR-dynamic/qir-driver.cpp b/src/Qir/Tests/QIR-dynamic/qir-driver.cpp similarity index 97% rename from src/QirRuntime/test/QIR-dynamic/qir-driver.cpp rename to src/Qir/Tests/QIR-dynamic/qir-driver.cpp index b96458c79a3..fc6a6129b8a 100644 --- a/src/QirRuntime/test/QIR-dynamic/qir-driver.cpp +++ b/src/Qir/Tests/QIR-dynamic/qir-driver.cpp @@ -1,36 +1,36 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include - -#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file -#include "catch.hpp" - -// Can manually add calls to DebugLog in the ll files for debugging. -extern "C" void DebugLog(int64_t value) -{ - std::cout << value << std::endl; -} -extern "C" void DebugLogPtr(char* value) -{ - std::cout << (const void*)value << std::endl; -} - -extern "C" void SetupQirToRunOnFullStateSimulator(); -extern "C" int64_t Microsoft__Quantum__Testing__QIR__QuantumRandomNumberGenerator__body(); // NOLINT -TEST_CASE("QIR: Generate a random number with full state simulator", "[qir]") -{ - SetupQirToRunOnFullStateSimulator(); - - const int ret1 = Microsoft__Quantum__Testing__QIR__QuantumRandomNumberGenerator__body(); - const int ret2 = Microsoft__Quantum__Testing__QIR__QuantumRandomNumberGenerator__body(); - const int ret3 = Microsoft__Quantum__Testing__QIR__QuantumRandomNumberGenerator__body(); - INFO( - std::string("Three random numbers: ") + std::to_string(ret1) + ", " + std::to_string(ret2) + ", " + - std::to_string(ret3)); - - // Check that the returned numbers are at least somewhat random... - CHECK(ret1 != ret2); - CHECK(ret1 != ret3); - CHECK(ret2 != ret3); -} +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include + +#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file +#include "catch.hpp" + +// Can manually add calls to DebugLog in the ll files for debugging. +extern "C" void DebugLog(int64_t value) +{ + std::cout << value << std::endl; +} +extern "C" void DebugLogPtr(char* value) +{ + std::cout << (const void*)value << std::endl; +} + +extern "C" void SetupQirToRunOnFullStateSimulator(); +extern "C" int64_t Microsoft__Quantum__Testing__QIR__QuantumRandomNumberGenerator__body(); // NOLINT +TEST_CASE("QIR: Generate a random number with full state simulator", "[qir]") +{ + SetupQirToRunOnFullStateSimulator(); + + const int ret1 = Microsoft__Quantum__Testing__QIR__QuantumRandomNumberGenerator__body(); + const int ret2 = Microsoft__Quantum__Testing__QIR__QuantumRandomNumberGenerator__body(); + const int ret3 = Microsoft__Quantum__Testing__QIR__QuantumRandomNumberGenerator__body(); + INFO( + std::string("Three random numbers: ") + std::to_string(ret1) + ", " + std::to_string(ret2) + ", " + + std::to_string(ret3)); + + // Check that the returned numbers are at least somewhat random... + CHECK(ret1 != ret2); + CHECK(ret1 != ret3); + CHECK(ret2 != ret3); +} diff --git a/src/Qir/Tests/QIR-dynamic/qsharp/qir-test-random.csproj b/src/Qir/Tests/QIR-dynamic/qsharp/qir-test-random.csproj new file mode 100644 index 00000000000..95dacab3142 --- /dev/null +++ b/src/Qir/Tests/QIR-dynamic/qsharp/qir-test-random.csproj @@ -0,0 +1,14 @@ + + + + Exe + netcoreapp3.1 + True + false + + + + + + + diff --git a/src/QirRuntime/test/QIR-dynamic/qir-test-random.qs b/src/Qir/Tests/QIR-dynamic/qsharp/qir-test-random.qs similarity index 96% rename from src/QirRuntime/test/QIR-dynamic/qir-test-random.qs rename to src/Qir/Tests/QIR-dynamic/qsharp/qir-test-random.qs index 7e1647bccb9..6a0b2a9787a 100644 --- a/src/QirRuntime/test/QIR-dynamic/qir-test-random.qs +++ b/src/Qir/Tests/QIR-dynamic/qsharp/qir-test-random.qs @@ -1,25 +1,25 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -namespace Microsoft.Quantum.Testing.QIR -{ - open Microsoft.Quantum.Intrinsic; - - @EntryPoint() - operation QuantumRandomNumberGenerator() : Int { - mutable randomNumber = 0; - - for (i in 1 .. 64) - { - using(q = Qubit()) - { - H(q); - set randomNumber = randomNumber <<< 1; - if (M(q) == One) { - set randomNumber += 1; - } - } - } - return randomNumber; - } +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Testing.QIR +{ + open Microsoft.Quantum.Intrinsic; + + @EntryPoint() + operation QuantumRandomNumberGenerator() : Int { + mutable randomNumber = 0; + + for (i in 1 .. 64) + { + using(q = Qubit()) + { + H(q); + set randomNumber = randomNumber <<< 1; + if (M(q) == One) { + set randomNumber += 1; + } + } + } + return randomNumber; + } } \ No newline at end of file diff --git a/src/Qir/Tests/QIR-static/CMakeLists.txt b/src/Qir/Tests/QIR-static/CMakeLists.txt new file mode 100644 index 00000000000..323d8222a7e --- /dev/null +++ b/src/Qir/Tests/QIR-static/CMakeLists.txt @@ -0,0 +1,38 @@ +set(TEST_FILES + qir-test-noqsharp.ll + qsharp/qir/qir-gen.ll +) + +#============================================================================== +# The executable target for QIR tests triggers the custom actions to compile ll files +# +add_executable(qir-static-tests + qir-driver.cpp + qir-test-conditionals.cpp + qir-test-math.cpp + qir-test-strings.cpp + qir-test-ouput.cpp + qir-test-other.cpp +) + +foreach(file ${TEST_FILES}) + target_source_from_qir(qir-static-tests ${file}) +endforeach() + +target_link_libraries(qir-static-tests PUBLIC + "-L${runtime_lib_path}" + -lMicrosoft.Quantum.Qir.Runtime + -lMicrosoft.Quantum.Qir.QSharp.Foundation + -lMicrosoft.Quantum.Qir.QSharp.Core +) + +target_include_directories(qir-static-tests PUBLIC + ${test_includes} + ${common_includes} + ${public_includes} +) +# target_compile_definitions(qir-static-tests PRIVATE EXPORT_QIR_API) + +install(TARGETS qir-static-tests RUNTIME DESTINATION "${CMAKE_BINARY_DIR}/bin") +add_unit_test(qir-static-tests) + diff --git a/src/QirRuntime/test/QIR-static/qir-driver.cpp b/src/Qir/Tests/QIR-static/qir-driver.cpp similarity index 94% rename from src/QirRuntime/test/QIR-static/qir-driver.cpp rename to src/Qir/Tests/QIR-static/qir-driver.cpp index f0c34c84d5a..5d8180e2206 100644 --- a/src/QirRuntime/test/QIR-static/qir-driver.cpp +++ b/src/Qir/Tests/QIR-static/qir-driver.cpp @@ -1,331 +1,335 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -#include -#include -#include -#include -#include -#include - -#include "CoreTypes.hpp" -#include "QirContext.hpp" -#include "QirTypes.hpp" -#include "QirRuntimeApi_I.hpp" -#include "SimFactory.hpp" -#include "SimulatorStub.hpp" -#include "QirRuntime.hpp" - -#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file -#include "catch.hpp" - -// Used by a couple test simulators. Catch's REQUIRE macro doesn't deal well with static class members so making it -// into a global constant. -constexpr int RELEASED = -1; - -using namespace Microsoft::Quantum; -using namespace std; - -// Can manually add calls to DebugLog in the ll files for debugging. -extern "C" void DebugLog(int64_t value) -{ - std::cout << value << std::endl; -} -extern "C" void DebugLogPtr(char* value) -{ - std::cout << (const void*)value << std::endl; -} - -/* -Forward declared `extern "C"` methods below are implemented in the *.ll files. Most of the files are generated by Q# -compiler, in which case the corresponding *.qs file was used as a source. Some files might have been authored manually -or manually edited. - -To update the *.ll files to a newer version: -- enlist and build qsharp-compiler -- find \qsc.exe and \QirCore.qs, \QirTarget.qs built files -- [if different] copy QirCore.qs and QirTarget.qs into the "compiler" folder -- run: qsc.exe build --qir s --build-exe --input name.qs compiler\qircore.qs compiler\qirtarget.qs --proj name -- the generated file name.ll will be placed into `s` folder -*/ - -// The function replaces array[index] with value, then creates a new array that consists of every other element up to -// index (starting from index backwards) and every element from index to the end. It returns the sum of elements in this -// new array -extern "C" int64_t Microsoft__Quantum__Testing__QIR__Test_Arrays( // NOLINT - int64_t count, - int64_t* array, - int64_t index, - int64_t val, - bool compilerDecoy); -TEST_CASE("QIR: Using 1D arrays", "[qir][qir.arr1d]") -{ - // re-enable tracking when https://github.com/microsoft/qsharp-compiler/issues/844 is fixed - QirContextScope qirctx(nullptr, false /*trackAllocatedObjects*/); - - constexpr int64_t n = 5; - int64_t values[n] = {0, 1, 2, 3, 4}; - - int64_t res = Microsoft__Quantum__Testing__QIR__Test_Arrays(n, values, 2, 42, false); - REQUIRE(res == (0 + 42) + (42 + 3 + 4)); -} - -extern "C" void Microsoft__Quantum__Testing__QIR__TestQubitResultManagement__body(); // NOLINT -struct QubitsResultsTestSimulator : public Microsoft::Quantum::SimulatorStub -{ - // no intelligent reuse, we just want to check that QIR releases all qubits - vector qubits; // released, or |0>, or |1> states (no entanglement allowed) - vector results = {0, 1}; // released, or Zero(0) or One(1) - - int GetQubitId(Qubit qubit) const - { - const int id = static_cast(reinterpret_cast(qubit)); - REQUIRE(id >= 0); - REQUIRE(id < this->qubits.size()); - - return id; - } - - int GetResultId(Result result) const - { - const int id = static_cast(reinterpret_cast(result)); - REQUIRE(id >= 0); - REQUIRE(id < this->results.size()); - - return id; - } - - Qubit AllocateQubit() override - { - qubits.push_back(0); - return reinterpret_cast(this->qubits.size() - 1); - } - - void ReleaseQubit(Qubit qubit) override - { - const int id = GetQubitId(qubit); - REQUIRE(this->qubits[id] != RELEASED); // no double-release - this->qubits[id] = RELEASED; - } - - void X(Qubit qubit) override - { - const int id = GetQubitId(qubit); - REQUIRE(this->qubits[id] != RELEASED); // the qubit must be alive - this->qubits[id] = 1 - this->qubits[id]; - } - - Result Measure(long numBases, PauliId bases[], long numTargets, Qubit targets[]) override - { - assert(numBases == 1 && "QubitsResultsTestSimulator doesn't support joint measurements"); - - const int id = GetQubitId(targets[0]); - REQUIRE(this->qubits[id] != RELEASED); // the qubit must be alive - this->results.push_back(this->qubits[id]); - return reinterpret_cast(this->results.size() - 1); - } - - bool AreEqualResults(Result r1, Result r2) override - { - int i1 = GetResultId(r1); - int i2 = GetResultId(r2); - REQUIRE(this->results[i1] != RELEASED); - REQUIRE(this->results[i2] != RELEASED); - - return (results[i1] == results[i2]); - } - - void ReleaseResult(Result result) override - { - int i = GetResultId(result); - REQUIRE(this->results[i] != RELEASED); // no double release - this->results[i] = RELEASED; - } - - Result UseZero() override - { - return reinterpret_cast(0); - } - - Result UseOne() override - { - return reinterpret_cast(1); - } -}; -TEST_CASE("QIR: allocating and releasing qubits and results", "[qir][qir.qubit][qir.result]") -{ - unique_ptr sim = make_unique(); - QirContextScope qirctx(sim.get(), true /*trackAllocatedObjects*/); - - REQUIRE_NOTHROW(Microsoft__Quantum__Testing__QIR__TestQubitResultManagement__body()); - - // check that all qubits have been released - for (size_t id = 0; id < sim->qubits.size(); id++) - { - INFO(std::string("unreleased qubit: ") + std::to_string(id)); - CHECK(sim->qubits[id] == RELEASED); - } - - // check that all results, allocated by measurements have been released - // TODO: enable after https://github.com/microsoft/qsharp-compiler/issues/780 is fixed - // for (size_t id = 2; id < sim->results.size(); id++) - // { - // INFO(std::string("unreleased results: ") + std::to_string(id)); - // CHECK(sim->results[id] == RELEASED); - // } -} - -#ifdef _WIN32 -// A non-sensical function that creates a 3D array with given dimensions, then projects on the index = 1 of the -// second dimension and returns a function of the sizes of the dimensions of the projection and a the provided value, -// that is written to the original array at [1,1,1] and then retrieved from [1,1]. -// Thus, all three dimensions must be at least 2. -extern "C" int64_t TestMultidimArrays(char value, int64_t dim0, int64_t dim1, int64_t dim2); -TEST_CASE("QIR: multidimensional arrays", "[qir][qir.arrMultid]") -{ - QirContextScope qirctx(nullptr, true /*trackAllocatedObjects*/); - - REQUIRE(42 + (2 + 8) / 2 == TestMultidimArrays(42, 2, 4, 8)); - REQUIRE(17 + (3 + 7) / 2 == TestMultidimArrays(17, 3, 5, 7)); -} -#else // not _WIN32 -// TODO: The bridge for variadic functions is broken on Linux! -#endif - -// Manually authored QIR to test dumping range [0..2..6] into string and then raising a failure with it -extern "C" void TestFailWithRangeString(int64_t start, int64_t step, int64_t end); -TEST_CASE("QIR: Report range in a failure message", "[qir][qir.range]") -{ - QirContextScope qirctx(nullptr, true /*trackAllocatedObjects*/); - - bool failed = false; - try - { - TestFailWithRangeString(0, 5, 42); - } - catch (const std::exception& e) - { - failed = true; - REQUIRE(std::string(e.what()) == "0..5..42"); - } - REQUIRE(failed); -} - -#if 0 // TODO: Q# compiler crashes generating QIR for TestPartials -// TestPartials subtracts the second argument from the first and returns the result. -extern "C" int64_t Microsoft__Quantum__Testing__QIR__TestPartials__body(int64_t, int64_t); // NOLINT -TEST_CASE("QIR: Partial application of a callable", "[qir][qir.partCallable]") -{ - QirContextScope qirctx(nullptr, true /*trackAllocatedObjects*/); - - const int64_t res = Microsoft__Quantum__Testing__QIR__TestPartials__body(42, 17); - REQUIRE(res == 42 - 17); -} -#endif - -// The Microsoft__Quantum__Testing__QIR__TestFunctors__body tests needs proper semantics of X and M, and nothing else. -// The validation is done inside the test and it would throw in case of failure. -struct FunctorsTestSimulator : public Microsoft::Quantum::SimulatorStub -{ - std::vector qubits; - - int GetQubitId(Qubit qubit) const - { - const int id = static_cast(reinterpret_cast(qubit)); - REQUIRE(id >= 0); - REQUIRE(id < this->qubits.size()); - return id; - } - - Qubit AllocateQubit() override - { - this->qubits.push_back(0); - return reinterpret_cast(this->qubits.size() - 1); - } - - void ReleaseQubit(Qubit qubit) override - { - const int id = GetQubitId(qubit); - REQUIRE(this->qubits[id] != RELEASED); - this->qubits[id] = RELEASED; - } - - void X(Qubit qubit) override - { - const int id = GetQubitId(qubit); - REQUIRE(this->qubits[id] != RELEASED); // the qubit must be alive - this->qubits[id] = 1 - this->qubits[id]; - } - - void ControlledX(long numControls, Qubit controls[], Qubit qubit) override - { - for (long i = 0; i < numControls; i++) - { - const int id = GetQubitId(controls[i]); - REQUIRE(this->qubits[id] != RELEASED); - if (this->qubits[id] == 0) - { - return; - } - } - X(qubit); - } - - Result Measure(long numBases, PauliId bases[], long numTargets, Qubit targets[]) override - { - assert(numBases == 1 && "FunctorsTestSimulator doesn't support joint measurements"); - - const int id = GetQubitId(targets[0]); - REQUIRE(this->qubits[id] != RELEASED); - return reinterpret_cast(this->qubits[id]); - } - - bool AreEqualResults(Result r1, Result r2) override - { - // those are bogus pointers but it's ok to compare them _as pointers_ - return (r1 == r2); - } - - void ReleaseResult(Result result) override {} // the results aren't allocated by this test simulator - - Result UseZero() override - { - return reinterpret_cast(0); - } - - Result UseOne() override - { - return reinterpret_cast(1); - } -}; -FunctorsTestSimulator* g_ctrqapi = nullptr; -static int g_cKCalls = 0; -static int g_cKCallsControlled = 0; -extern "C" void Microsoft__Quantum__Testing__QIR__TestFunctors__body(); // NOLINT -extern "C" void Microsoft__Quantum__Testing__QIR__TestFunctorsNoArgs__body(); // NOLINT -extern "C" void __quantum__qis__k__body(Qubit q) // NOLINT -{ - g_cKCalls++; - g_ctrqapi->X(q); -} -extern "C" void __quantum__qis__k__ctl(QirArray* controls, Qubit q) // NOLINT -{ - g_cKCallsControlled++; - g_ctrqapi->ControlledX(controls->count, reinterpret_cast(controls->buffer), q); -} -TEST_CASE("QIR: application of nested controlled functor", "[qir][qir.functor]") -{ - unique_ptr qapi = make_unique(); - QirContextScope qirctx(qapi.get(), true /*trackAllocatedObjects*/); - g_ctrqapi = qapi.get(); - - CHECK_NOTHROW(Microsoft__Quantum__Testing__QIR__TestFunctors__body()); - - const int cKCalls = g_cKCalls; - const int cKCallsControlled = g_cKCallsControlled; - CHECK_NOTHROW(Microsoft__Quantum__Testing__QIR__TestFunctorsNoArgs__body()); - CHECK(g_cKCalls - cKCalls == 3); - CHECK(g_cKCallsControlled - cKCallsControlled == 5); - - g_ctrqapi = nullptr; -} +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include +#include +#include +#include +#include +#include + +#include "CoreTypes.hpp" +#include "QirContext.hpp" +#include "QirTypes.hpp" +#include "QirRuntimeApi_I.hpp" +#include "SimFactory.hpp" +#include "SimulatorStub.hpp" +#include "QirRuntime.hpp" + +#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file +#include "catch.hpp" + +// Used by a couple test simulators. Catch's REQUIRE macro doesn't deal well with static class members so making it +// into a global constant. +constexpr int RELEASED = -1; + +using namespace Microsoft::Quantum; +using namespace std; + +// Can manually add calls to DebugLog in the ll files for debugging. +extern "C" void DebugLog(int64_t value) +{ + std::cout << value << std::endl; +} +extern "C" void DebugLogPtr(char* value) +{ + std::cout << (const void*)value << std::endl; +} + +/* +Forward declared `extern "C"` methods below are implemented in the *.ll files. Most of the files are generated by Q# +compiler, in which case the corresponding *.qs file was used as a source. Some files might have been authored manually +or manually edited. + +To update the *.ll files to a newer version: +- enlist and build qsharp-compiler +- find \qsc.exe and \QirCore.qs, \QirTarget.qs built files +- [if different] copy QirCore.qs and QirTarget.qs into the "compiler" folder +- run: qsc.exe build --qir s --build-exe --input name.qs compiler\qircore.qs compiler\qirtarget.qs --proj name +- the generated file name.ll will be placed into `s` folder +*/ + +struct Array { + int64_t itemSize; + void* buffer; +}; + +// The function replaces array[index] with value, then creates a new array that consists of every other element up to +// index (starting from index backwards) and every element from index to the end. It returns the sum of elements in this +// new array +extern "C" int64_t Microsoft__Quantum__Testing__QIR__Test_Arrays__Interop( // NOLINT + Array* array, + int64_t index, + int64_t val, + bool compilerDecoy); +TEST_CASE("QIR: Using 1D arrays", "[qir][qir.arr1d]") +{ + QirContextScope qirctx(nullptr, true /*trackAllocatedObjects*/); + + constexpr int64_t n = 5; + int64_t values[n] = {0, 1, 2, 3, 4}; + auto array = Array{5, values}; + + int64_t res = Microsoft__Quantum__Testing__QIR__Test_Arrays__Interop(&array, 2, 42, false); + REQUIRE(res == (0 + 42) + (42 + 3 + 4)); +} + +extern "C" void Microsoft__Quantum__Testing__QIR__TestQubitResultManagement__body(); // NOLINT +struct QubitsResultsTestSimulator : public Microsoft::Quantum::SimulatorStub +{ + // no intelligent reuse, we just want to check that QIR releases all qubits + vector qubits; // released, or |0>, or |1> states (no entanglement allowed) + vector results = {0, 1}; // released, or Zero(0) or One(1) + + int GetQubitId(Qubit qubit) const + { + const int id = static_cast(reinterpret_cast(qubit)); + REQUIRE(id >= 0); + REQUIRE(id < this->qubits.size()); + + return id; + } + + int GetResultId(Result result) const + { + const int id = static_cast(reinterpret_cast(result)); + REQUIRE(id >= 0); + REQUIRE(id < this->results.size()); + + return id; + } + + Qubit AllocateQubit() override + { + qubits.push_back(0); + return reinterpret_cast(this->qubits.size() - 1); + } + + void ReleaseQubit(Qubit qubit) override + { + const int id = GetQubitId(qubit); + REQUIRE(this->qubits[id] != RELEASED); // no double-release + this->qubits[id] = RELEASED; + } + + void X(Qubit qubit) override + { + const int id = GetQubitId(qubit); + REQUIRE(this->qubits[id] != RELEASED); // the qubit must be alive + this->qubits[id] = 1 - this->qubits[id]; + } + + Result Measure(long numBases, PauliId bases[], long numTargets, Qubit targets[]) override + { + assert(numBases == 1 && "QubitsResultsTestSimulator doesn't support joint measurements"); + + const int id = GetQubitId(targets[0]); + REQUIRE(this->qubits[id] != RELEASED); // the qubit must be alive + this->results.push_back(this->qubits[id]); + return reinterpret_cast(this->results.size() - 1); + } + + bool AreEqualResults(Result r1, Result r2) override + { + int i1 = GetResultId(r1); + int i2 = GetResultId(r2); + REQUIRE(this->results[i1] != RELEASED); + REQUIRE(this->results[i2] != RELEASED); + + return (results[i1] == results[i2]); + } + + void ReleaseResult(Result result) override + { + int i = GetResultId(result); + REQUIRE(this->results[i] != RELEASED); // no double release + this->results[i] = RELEASED; + } + + Result UseZero() override + { + return reinterpret_cast(0); + } + + Result UseOne() override + { + return reinterpret_cast(1); + } +}; +TEST_CASE("QIR: allocating and releasing qubits and results", "[qir][qir.qubit][qir.result]") +{ + unique_ptr sim = make_unique(); + QirContextScope qirctx(sim.get(), true /*trackAllocatedObjects*/); + + REQUIRE_NOTHROW(Microsoft__Quantum__Testing__QIR__TestQubitResultManagement__body()); + + // check that all qubits have been released + for (size_t id = 0; id < sim->qubits.size(); id++) + { + INFO(std::string("unreleased qubit: ") + std::to_string(id)); + CHECK(sim->qubits[id] == RELEASED); + } + + // check that all results, allocated by measurements have been released + // TODO: enable after https://github.com/microsoft/qsharp-compiler/issues/780 is fixed + // for (size_t id = 2; id < sim->results.size(); id++) + // { + // INFO(std::string("unreleased results: ") + std::to_string(id)); + // CHECK(sim->results[id] == RELEASED); + // } +} + +#ifdef _WIN32 +// A non-sensical function that creates a 3D array with given dimensions, then projects on the index = 1 of the +// second dimension and returns a function of the sizes of the dimensions of the projection and a the provided value, +// that is written to the original array at [1,1,1] and then retrieved from [1,1]. +// Thus, all three dimensions must be at least 2. +extern "C" int64_t TestMultidimArrays(char value, int64_t dim0, int64_t dim1, int64_t dim2); +TEST_CASE("QIR: multidimensional arrays", "[qir][qir.arrMultid]") +{ + QirContextScope qirctx(nullptr, true /*trackAllocatedObjects*/); + + REQUIRE(42 + (2 + 8) / 2 == TestMultidimArrays(42, 2, 4, 8)); + REQUIRE(17 + (3 + 7) / 2 == TestMultidimArrays(17, 3, 5, 7)); +} +#else // not _WIN32 +// TODO: The bridge for variadic functions is broken on Linux! +#endif + +// Manually authored QIR to test dumping range [0..2..6] into string and then raising a failure with it +extern "C" void TestFailWithRangeString(int64_t start, int64_t step, int64_t end); +TEST_CASE("QIR: Report range in a failure message", "[qir][qir.range]") +{ + QirContextScope qirctx(nullptr, true /*trackAllocatedObjects*/); + + bool failed = false; + try + { + TestFailWithRangeString(0, 5, 42); + } + catch (const std::exception& e) + { + failed = true; + REQUIRE(std::string(e.what()) == "0..5..42"); + } + REQUIRE(failed); +} + +#if 0 // TODO: Q# compiler crashes generating QIR for TestPartials +// TestPartials subtracts the second argument from the first and returns the result. +extern "C" int64_t Microsoft__Quantum__Testing__QIR__TestPartials__body(int64_t, int64_t); // NOLINT +TEST_CASE("QIR: Partial application of a callable", "[qir][qir.partCallable]") +{ + QirContextScope qirctx(nullptr, true /*trackAllocatedObjects*/); + + const int64_t res = Microsoft__Quantum__Testing__QIR__TestPartials__body(42, 17); + REQUIRE(res == 42 - 17); +} +#endif + +// The Microsoft__Quantum__Testing__QIR__TestFunctors__body tests needs proper semantics of X and M, and nothing else. +// The validation is done inside the test and it would throw in case of failure. +struct FunctorsTestSimulator : public Microsoft::Quantum::SimulatorStub +{ + std::vector qubits; + + int GetQubitId(Qubit qubit) const + { + const int id = static_cast(reinterpret_cast(qubit)); + REQUIRE(id >= 0); + REQUIRE(id < this->qubits.size()); + return id; + } + + Qubit AllocateQubit() override + { + this->qubits.push_back(0); + return reinterpret_cast(this->qubits.size() - 1); + } + + void ReleaseQubit(Qubit qubit) override + { + const int id = GetQubitId(qubit); + REQUIRE(this->qubits[id] != RELEASED); + this->qubits[id] = RELEASED; + } + + void X(Qubit qubit) override + { + const int id = GetQubitId(qubit); + REQUIRE(this->qubits[id] != RELEASED); // the qubit must be alive + this->qubits[id] = 1 - this->qubits[id]; + } + + void ControlledX(long numControls, Qubit controls[], Qubit qubit) override + { + for (long i = 0; i < numControls; i++) + { + const int id = GetQubitId(controls[i]); + REQUIRE(this->qubits[id] != RELEASED); + if (this->qubits[id] == 0) + { + return; + } + } + X(qubit); + } + + Result Measure(long numBases, PauliId bases[], long numTargets, Qubit targets[]) override + { + assert(numBases == 1 && "FunctorsTestSimulator doesn't support joint measurements"); + + const int id = GetQubitId(targets[0]); + REQUIRE(this->qubits[id] != RELEASED); + return reinterpret_cast(this->qubits[id]); + } + + bool AreEqualResults(Result r1, Result r2) override + { + // those are bogus pointers but it's ok to compare them _as pointers_ + return (r1 == r2); + } + + void ReleaseResult(Result result) override {} // the results aren't allocated by this test simulator + + Result UseZero() override + { + return reinterpret_cast(0); + } + + Result UseOne() override + { + return reinterpret_cast(1); + } +}; +FunctorsTestSimulator* g_ctrqapi = nullptr; +static int g_cKCalls = 0; +static int g_cKCallsControlled = 0; +extern "C" void Microsoft__Quantum__Testing__QIR__TestFunctors__body(); // NOLINT +extern "C" void Microsoft__Quantum__Testing__QIR__TestFunctorsNoArgs__body(); // NOLINT +extern "C" void __quantum__qis__k__body(Qubit q) // NOLINT +{ + g_cKCalls++; + g_ctrqapi->X(q); +} +extern "C" void __quantum__qis__k__ctl(QirArray* controls, Qubit q) // NOLINT +{ + g_cKCallsControlled++; + g_ctrqapi->ControlledX(controls->count, reinterpret_cast(controls->buffer), q); +} +TEST_CASE("QIR: application of nested controlled functor", "[qir][qir.functor]") +{ + unique_ptr qapi = make_unique(); + QirContextScope qirctx(qapi.get(), true /*trackAllocatedObjects*/); + g_ctrqapi = qapi.get(); + + CHECK_NOTHROW(Microsoft__Quantum__Testing__QIR__TestFunctors__body()); + + const int cKCalls = g_cKCalls; + const int cKCallsControlled = g_cKCallsControlled; + CHECK_NOTHROW(Microsoft__Quantum__Testing__QIR__TestFunctorsNoArgs__body()); + CHECK(g_cKCalls - cKCalls == 3); + CHECK(g_cKCallsControlled - cKCallsControlled == 5); + + g_ctrqapi = nullptr; +} diff --git a/src/QirRuntime/test/QIR-static/qir-test-conditionals.cpp b/src/Qir/Tests/QIR-static/qir-test-conditionals.cpp similarity index 100% rename from src/QirRuntime/test/QIR-static/qir-test-conditionals.cpp rename to src/Qir/Tests/QIR-static/qir-test-conditionals.cpp diff --git a/src/QirRuntime/test/QIR-static/qir-test-math.cpp b/src/Qir/Tests/QIR-static/qir-test-math.cpp similarity index 86% rename from src/QirRuntime/test/QIR-static/qir-test-math.cpp rename to src/Qir/Tests/QIR-static/qir-test-math.cpp index b46b2ed4a1e..545d869c436 100644 --- a/src/QirRuntime/test/QIR-static/qir-test-math.cpp +++ b/src/Qir/Tests/QIR-static/qir-test-math.cpp @@ -22,6 +22,7 @@ extern "C" uint64_t Microsoft__Quantum__Testing__QIR__Math__CoshTest__body(); extern "C" uint64_t Microsoft__Quantum__Testing__QIR__Math__TanhTest__body(); // NOLINT extern "C" uint64_t Microsoft__Quantum__Testing__QIR__Math__IeeeRemainderTest__body(); // NOLINT extern "C" uint64_t Microsoft__Quantum__Testing__QIR__Math__TestDrawRandomInt__body(int64_t min, int64_t max); // NOLINT +extern "C" double Microsoft__Quantum__Testing__QIR__Math__TestDrawRandomDouble__body(double min, double max); // NOLINT TEST_CASE("QIR: Math.Sqrt", "[qir.math][qir.Math.Sqrt]") { @@ -97,7 +98,7 @@ TEST_CASE("QIR: Math.DrawRandomInt", "[qir.math][qir.Math.DrawRandomInt]") const uint64_t qsRndNum = Microsoft__Quantum__Testing__QIR__Math__TestDrawRandomInt__body(std::numeric_limits::min(), std::numeric_limits::max()); - const uint64_t cppRndNum = Quantum::Qis::Internal::GetLastGeneratedRandomNumber(); // This call must be done + const uint64_t cppRndNum = Quantum::Qis::Internal::GetLastGeneratedRandomI64(); // This call must be done // _after_ the Microsoft__Quantum__Testing__QIR__Math__TestDrawRandomInt__body(). REQUIRE(qsRndNum == cppRndNum); } @@ -112,7 +113,13 @@ TEST_CASE("QIR: Math.DrawRandomInt", "[qir.math][qir.Math.DrawRandomInt]") } catch (std::runtime_error const& exc) { - REQUIRE(0 == strcmp(exc.what(), Quantum::Qis::Internal::excStrDrawRandomInt)); + REQUIRE(0 == strcmp(exc.what(), Quantum::Qis::Internal::excStrDrawRandomVal)); + } + + // Test equal minimum and maximum: + for(uint64_t num: { -5, 0, 3 } ) + { + REQUIRE(Microsoft__Quantum__Testing__QIR__Math__TestDrawRandomInt__body(num, num) == num); } // There is a strong difference in the opinions about how the random number generator must be tested. @@ -201,3 +208,31 @@ TEST_CASE("QIR: Math.DrawRandomInt", "[qir.math][qir.Math.DrawRandomInt]") // } } // TEST_CASE("QIR: Math.DrawRandomInt", "[qir.math][qir.Math.DrawRandomInt]") + +TEST_CASE("QIR: Math.DrawRandomDouble", "[qir.math][qir.Math.DrawRandomDouble]") +{ + // Test that the Q# random number generator is a wrapper around the C++ generator: + size_t times = 1000; + while(--times) + { + const double qsRndNum = + Microsoft__Quantum__Testing__QIR__Math__TestDrawRandomDouble__body(std::numeric_limits::min(), + std::numeric_limits::max()); + const double cppRndNum = Quantum::Qis::Internal::GetLastGeneratedRandomDouble(); // This call must be done + // _after_ the Microsoft__Quantum__Testing__QIR__Math__TestDrawRandomDouble__body(). + REQUIRE(qsRndNum == cppRndNum); + } + + // Make sure the correct exception is thrown if min > max: + REQUIRE_THROWS_AS(Microsoft__Quantum__Testing__QIR__Math__TestDrawRandomDouble__body(10.0, 5.0), std::runtime_error); + + // Check the exception string: + try + { + (void)Microsoft__Quantum__Testing__QIR__Math__TestDrawRandomDouble__body(10.0, 5.0); + } + catch (std::runtime_error const& exc) + { + REQUIRE(0 == strcmp(exc.what(), Quantum::Qis::Internal::excStrDrawRandomVal)); + } +} // TEST_CASE("QIR: Math.DrawRandomDouble", "[qir.math][qir.Math.DrawRandomDouble]") diff --git a/src/QirRuntime/test/QIR-static/qir-test-noqsharp.ll b/src/Qir/Tests/QIR-static/qir-test-noqsharp.ll similarity index 96% rename from src/QirRuntime/test/QIR-static/qir-test-noqsharp.ll rename to src/Qir/Tests/QIR-static/qir-test-noqsharp.ll index 72ef01af60c..3d08b24f10c 100644 --- a/src/QirRuntime/test/QIR-static/qir-test-noqsharp.ll +++ b/src/Qir/Tests/QIR-static/qir-test-noqsharp.ll @@ -1,49 +1,49 @@ -%Range = type { i64, i64, i64 } -%Array = type opaque -%String = type opaque - -@EmptyRange = internal constant %Range { i64 0, i64 1, i64 -1 } -declare %Array* @__quantum__rt__array_create(i32, i32, ...) -declare i64 @__quantum__rt__array_get_size(%Array*, i32) -declare i8* @__quantum__rt__array_get_element_ptr(%Array*, ...) -declare i32 @__quantum__rt__array_get_dim(%Array*) -declare %Array* @__quantum__rt__array_project(%Array*, i32, i64) -declare void @__quantum__rt__array_update_reference_count(%Array*, i64) -declare void @DebugLog(i64) - -; manually authored test for multi-dimensional arrays (Q# doesn't support multi-dimentional arrays yet) -define i64 @TestMultidimArrays(i8 %val, i64 %dim0, i64 %dim1, i64 %dim2) -{ - %.ar = call %Array* (i32, i32, ...) @__quantum__rt__array_create(i32 1, i32 3, i64 %dim0, i64 %dim1, i64 %dim2) - %elem_ptr = call i8* (%Array*, ...) @__quantum__rt__array_get_element_ptr(%Array* %.ar, i64 1, i64 1, i64 1) - store i8 %val, i8* %elem_ptr - %.project = call %Array* @__quantum__rt__array_project(%Array* %.ar, i32 1, i64 1) - %project_dims = call i32 @__quantum__rt__array_get_dim(%Array* %.project) - %project_dim0 = call i64 @__quantum__rt__array_get_size(%Array* %.project, i32 0) - %project_dim1 = call i64 @__quantum__rt__array_get_size(%Array* %.project, i32 1) - %project_elem_ptr = call i8* (%Array*, ...) @__quantum__rt__array_get_element_ptr(%Array* %.project, i64 1, i64 1) - %project_val = load i8, i8* %project_elem_ptr - %val64 = sext i8 %project_val to i64 - - call void @__quantum__rt__array_update_reference_count(%Array* %.ar, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %.project, i64 -1) - - %t1 = add i64 %project_dim0, %project_dim1 - %t2 = sext i32 %project_dims to i64 - %av = udiv i64 %t1, %t2 - %t3 = add i64 %av, %val64 - ret i64 %t3 -} - -; manually authored test for dumping range into a string and raising a failure with it -declare %String* @__quantum__rt__range_to_string(%Range) -declare void @__quantum__rt__fail(%String*) -define void @TestFailWithRangeString(i64 %start, i64 %step, i64 %end){ - %re = load %Range, %Range* @EmptyRange - %r0 = insertvalue %Range %re, i64 %start, 0 - %r1 = insertvalue %Range %r0, i64 %step, 1 - %r2 = insertvalue %Range %r1, i64 %end, 2 - %str = call %String* @__quantum__rt__range_to_string(%Range %r2) - call void @__quantum__rt__fail(%String* %str) - ret void -} +%Range = type { i64, i64, i64 } +%Array = type opaque +%String = type opaque + +@EmptyRange = internal constant %Range { i64 0, i64 1, i64 -1 } +declare %Array* @__quantum__rt__array_create(i32, i32, ...) +declare i64 @__quantum__rt__array_get_size(%Array*, i32) +declare i8* @__quantum__rt__array_get_element_ptr(%Array*, ...) +declare i32 @__quantum__rt__array_get_dim(%Array*) +declare %Array* @__quantum__rt__array_project(%Array*, i32, i64) +declare void @__quantum__rt__array_update_reference_count(%Array*, i32) +declare void @DebugLog(i64) + +; manually authored test for multi-dimensional arrays (Q# doesn't support multi-dimentional arrays yet) +define i64 @TestMultidimArrays(i8 %val, i64 %dim0, i64 %dim1, i64 %dim2) +{ + %.ar = call %Array* (i32, i32, ...) @__quantum__rt__array_create(i32 1, i32 3, i64 %dim0, i64 %dim1, i64 %dim2) + %elem_ptr = call i8* (%Array*, ...) @__quantum__rt__array_get_element_ptr(%Array* %.ar, i64 1, i64 1, i64 1) + store i8 %val, i8* %elem_ptr + %.project = call %Array* @__quantum__rt__array_project(%Array* %.ar, i32 1, i64 1) + %project_dims = call i32 @__quantum__rt__array_get_dim(%Array* %.project) + %project_dim0 = call i64 @__quantum__rt__array_get_size(%Array* %.project, i32 0) + %project_dim1 = call i64 @__quantum__rt__array_get_size(%Array* %.project, i32 1) + %project_elem_ptr = call i8* (%Array*, ...) @__quantum__rt__array_get_element_ptr(%Array* %.project, i64 1, i64 1) + %project_val = load i8, i8* %project_elem_ptr + %val64 = sext i8 %project_val to i64 + + call void @__quantum__rt__array_update_reference_count(%Array* %.ar, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %.project, i32 -1) + + %t1 = add i64 %project_dim0, %project_dim1 + %t2 = sext i32 %project_dims to i64 + %av = udiv i64 %t1, %t2 + %t3 = add i64 %av, %val64 + ret i64 %t3 +} + +; manually authored test for dumping range into a string and raising a failure with it +declare %String* @__quantum__rt__range_to_string(%Range) +declare void @__quantum__rt__fail(%String*) +define void @TestFailWithRangeString(i64 %start, i64 %step, i64 %end){ + %re = load %Range, %Range* @EmptyRange + %r0 = insertvalue %Range %re, i64 %start, 0 + %r1 = insertvalue %Range %r0, i64 %step, 1 + %r2 = insertvalue %Range %r1, i64 %end, 2 + %str = call %String* @__quantum__rt__range_to_string(%Range %r2) + call void @__quantum__rt__fail(%String* %str) + ret void +} diff --git a/src/QirRuntime/test/QIR-static/qir-test-other.cpp b/src/Qir/Tests/QIR-static/qir-test-other.cpp similarity index 100% rename from src/QirRuntime/test/QIR-static/qir-test-other.cpp rename to src/Qir/Tests/QIR-static/qir-test-other.cpp diff --git a/src/QirRuntime/test/QIR-static/qir-test-ouput.cpp b/src/Qir/Tests/QIR-static/qir-test-ouput.cpp similarity index 95% rename from src/QirRuntime/test/QIR-static/qir-test-ouput.cpp rename to src/Qir/Tests/QIR-static/qir-test-ouput.cpp index a7d47893926..9331edc0a0f 100644 --- a/src/QirRuntime/test/QIR-static/qir-test-ouput.cpp +++ b/src/Qir/Tests/QIR-static/qir-test-ouput.cpp @@ -6,8 +6,7 @@ #include "catch.hpp" #include "QirTypes.hpp" -#include "SimFactory.hpp" -#include "qsharp__foundation_internal.hpp" +#include "QirRuntime.hpp" extern "C" void Microsoft__Quantum__Testing__QIR__Out__MessageTest__body(void*); // NOLINT diff --git a/src/QirRuntime/test/QIR-static/qir-test-strings.cpp b/src/Qir/Tests/QIR-static/qir-test-strings.cpp similarity index 100% rename from src/QirRuntime/test/QIR-static/qir-test-strings.cpp rename to src/Qir/Tests/QIR-static/qir-test-strings.cpp diff --git a/src/QirRuntime/test/QIR-static/qsharp/Math.qs b/src/Qir/Tests/QIR-static/qsharp/Math.qs similarity index 94% rename from src/QirRuntime/test/QIR-static/qsharp/Math.qs rename to src/Qir/Tests/QIR-static/qsharp/Math.qs index 6edba1a7860..bedfc70a1c8 100644 --- a/src/QirRuntime/test/QIR-static/qsharp/Math.qs +++ b/src/Qir/Tests/QIR-static/qsharp/Math.qs @@ -1,34 +1,34 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -namespace Microsoft.Quantum.Intrinsic { - - open Microsoft.Quantum.Targeting; - open Microsoft.Quantum.Core; - - @Inline() - function NAN() : Double { - body intrinsic; - } - - @Inline() - function IsNan(d: Double) : Bool { - body intrinsic; - } - - @Inline() - function INFINITY() : Double { - body intrinsic; - } - - @Inline() - function IsInf(d: Double) : Bool { - body intrinsic; - } - - @Inline() - function IsNegativeInfinity(d : Double) : Bool { - body intrinsic; - } - -} +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Intrinsic { + + open Microsoft.Quantum.Targeting; + open Microsoft.Quantum.Core; + + @Inline() + function NAN() : Double { + body intrinsic; + } + + @Inline() + function IsNan(d: Double) : Bool { + body intrinsic; + } + + @Inline() + function INFINITY() : Double { + body intrinsic; + } + + @Inline() + function IsInf(d: Double) : Bool { + body intrinsic; + } + + @Inline() + function IsNegativeInfinity(d : Double) : Bool { + body intrinsic; + } + +} diff --git a/src/QirRuntime/test/QIR-static/qsharp/qir-gen.csproj b/src/Qir/Tests/QIR-static/qsharp/qir-gen.csproj similarity index 75% rename from src/QirRuntime/test/QIR-static/qsharp/qir-gen.csproj rename to src/Qir/Tests/QIR-static/qsharp/qir-gen.csproj index 75a033a2193..95dacab3142 100644 --- a/src/QirRuntime/test/QIR-static/qsharp/qir-gen.csproj +++ b/src/Qir/Tests/QIR-static/qsharp/qir-gen.csproj @@ -1,15 +1,14 @@ - - - - Exe - netcoreapp3.1 - True - false - false - - - - - - - + + + + Exe + netcoreapp3.1 + True + false + + + + + + + diff --git a/src/QirRuntime/test/QIR-static/qsharp/qir-test-arrays.qs b/src/Qir/Tests/QIR-static/qsharp/qir-test-arrays.qs similarity index 97% rename from src/QirRuntime/test/QIR-static/qsharp/qir-test-arrays.qs rename to src/Qir/Tests/QIR-static/qsharp/qir-test-arrays.qs index efe2e706db7..67b966a3cd9 100644 --- a/src/QirRuntime/test/QIR-static/qsharp/qir-test-arrays.qs +++ b/src/Qir/Tests/QIR-static/qsharp/qir-test-arrays.qs @@ -57,6 +57,7 @@ namespace Microsoft.Quantum.Testing.QIR { let res19 = ParityTest(); let res20 = PauliArrayAsIntTest(); let res21 = PauliArrayAsIntFailTest(); + let res22 = TestDrawRandomDouble(0.0, 1.0); MessageTest("Test"); // Conditionals: diff --git a/src/QirRuntime/test/QIR-static/qsharp/qir-test-conditionals.qs b/src/Qir/Tests/QIR-static/qsharp/qir-test-conditionals.qs similarity index 97% rename from src/QirRuntime/test/QIR-static/qsharp/qir-test-conditionals.qs rename to src/Qir/Tests/QIR-static/qsharp/qir-test-conditionals.qs index 28a1b755a64..00a9919c956 100644 --- a/src/QirRuntime/test/QIR-static/qsharp/qir-test-conditionals.qs +++ b/src/Qir/Tests/QIR-static/qsharp/qir-test-conditionals.qs @@ -1,63 +1,63 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. -namespace Microsoft.Quantum.Testing.QIR { - open Microsoft.Quantum.Intrinsic; - open Microsoft.Quantum.Simulation.QuantumProcessor.Extensions; - - operation TestApplyIf() : Unit { - use q1 = Qubit(); - use q2 = Qubit(); - - let r1 = M(q1); // expected: r1 = Zero - X(q2); - let r2 = M(q2); // expected: r2 = One - - ApplyIfElseR(r1, (X, q1), (Y, q1)); - ApplyIfElseR(r2, (Y, q1), (X, q1)); - - // Other variants - ApplyIfElseRA(r1, (X, q1), (Y, q1)); - ApplyIfElseRC(r1, (X, q1), (Y, q1)); - ApplyIfElseRCA(r1, (X, q1), (Y, q1)); - ApplyIfOne(r2, (X, q1)); - ApplyIfZero(r1, (X, q1)); - } - - operation TestApplyIfWithFunctors() : Unit { - use q1 = Qubit(); - use q2 = Qubit(); - - let r1 = M(q1); - X(q2); - let r2 = M(q2); - - Adjoint ApplyIfElseRCA(r1, (X, q1), (Y, q1)); - Controlled ApplyIfElseRCA([q2], (r1, (X, q1), (Y, q1))); - Adjoint Controlled ApplyIfElseRCA([q2], (r1, (X, q1), (Y, q1))); - Adjoint ApplyIfElseRA(r1, (X, q1), (Y, q1)); - Controlled ApplyIfElseRC([q2], (r1, (X, q1), (Y, q1))); - Adjoint ApplyIfOneA(r2, (X, q1)); - Controlled ApplyIfOneC([q2], (r2, (X, q1))); - Adjoint Controlled ApplyIfOneCA([q2], (r2, (X, q1))); - Adjoint ApplyIfZeroA(r1, (X, q1)); - Controlled ApplyIfZeroC([q2], (r1, (X, q1))); - Adjoint Controlled ApplyIfZeroCA([q2], (r1, (X, q1))); - } - - operation TestApplyConditionally() : Unit { - use q1 = Qubit(); - use q2 = Qubit(); - - let r1 = M(q1); - X(q2); - let r2 = M(q2); - - ApplyConditionally([r1], [r2], (Y, q1), (X, q1)); - ApplyConditionally([r1, One], [Zero, r2], (X, q1), (Y, q1)); - - Adjoint ApplyConditionallyA([r1], [r2], (Y, q1), (X, q1)); - Controlled ApplyConditionallyC([q2], ([r1], [r2], (Y, q1), (X, q1))); - Adjoint Controlled ApplyConditionallyCA([q2], ([r1], [r2], (Y, q1), (X, q1))); - } - +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +namespace Microsoft.Quantum.Testing.QIR { + open Microsoft.Quantum.Intrinsic; + open Microsoft.Quantum.Simulation.QuantumProcessor.Extensions; + + operation TestApplyIf() : Unit { + use q1 = Qubit(); + use q2 = Qubit(); + + let r1 = M(q1); // expected: r1 = Zero + X(q2); + let r2 = M(q2); // expected: r2 = One + + ApplyIfElseR(r1, (X, q1), (Y, q1)); + ApplyIfElseR(r2, (Y, q1), (X, q1)); + + // Other variants + ApplyIfElseRA(r1, (X, q1), (Y, q1)); + ApplyIfElseRC(r1, (X, q1), (Y, q1)); + ApplyIfElseRCA(r1, (X, q1), (Y, q1)); + ApplyIfOne(r2, (X, q1)); + ApplyIfZero(r1, (X, q1)); + } + + operation TestApplyIfWithFunctors() : Unit { + use q1 = Qubit(); + use q2 = Qubit(); + + let r1 = M(q1); + X(q2); + let r2 = M(q2); + + Adjoint ApplyIfElseRCA(r1, (X, q1), (Y, q1)); + Controlled ApplyIfElseRCA([q2], (r1, (X, q1), (Y, q1))); + Adjoint Controlled ApplyIfElseRCA([q2], (r1, (X, q1), (Y, q1))); + Adjoint ApplyIfElseRA(r1, (X, q1), (Y, q1)); + Controlled ApplyIfElseRC([q2], (r1, (X, q1), (Y, q1))); + Adjoint ApplyIfOneA(r2, (X, q1)); + Controlled ApplyIfOneC([q2], (r2, (X, q1))); + Adjoint Controlled ApplyIfOneCA([q2], (r2, (X, q1))); + Adjoint ApplyIfZeroA(r1, (X, q1)); + Controlled ApplyIfZeroC([q2], (r1, (X, q1))); + Adjoint Controlled ApplyIfZeroCA([q2], (r1, (X, q1))); + } + + operation TestApplyConditionally() : Unit { + use q1 = Qubit(); + use q2 = Qubit(); + + let r1 = M(q1); + X(q2); + let r2 = M(q2); + + ApplyConditionally([r1], [r2], (Y, q1), (X, q1)); + ApplyConditionally([r1, One], [Zero, r2], (X, q1), (Y, q1)); + + Adjoint ApplyConditionallyA([r1], [r2], (Y, q1), (X, q1)); + Controlled ApplyConditionallyC([q2], ([r1], [r2], (Y, q1), (X, q1))); + Adjoint Controlled ApplyConditionallyCA([q2], ([r1], [r2], (Y, q1), (X, q1))); + } + } \ No newline at end of file diff --git a/src/QirRuntime/test/QIR-static/qsharp/qir-test-functors.qs b/src/Qir/Tests/QIR-static/qsharp/qir-test-functors.qs similarity index 96% rename from src/QirRuntime/test/QIR-static/qsharp/qir-test-functors.qs rename to src/Qir/Tests/QIR-static/qsharp/qir-test-functors.qs index 0d8c283dc87..4bc6b8cb38b 100644 --- a/src/QirRuntime/test/QIR-static/qsharp/qir-test-functors.qs +++ b/src/Qir/Tests/QIR-static/qsharp/qir-test-functors.qs @@ -1,106 +1,106 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -// For the test to pass implement K to be the same as X. We need it for the test, because the standard bridge doesn't -// support multi-controlled X. -namespace Microsoft.Quantum.Intrinsic { - open Microsoft.Quantum.Core; - @Inline() - operation K(q : Qubit) : Unit - is Adj+Ctl { - body intrinsic; - adjoint self; - controlled intrinsic; - } -} - -namespace Microsoft.Quantum.Testing.QIR { - open Microsoft.Quantum.Intrinsic; - - operation Qop(q : Qubit, n : Int) : Unit - is Adj+Ctl { - body (...) { - if n%2 == 1 { K(q); } - } - adjoint self; - controlled (ctrls, ...) { - if n%2 == 1 { Controlled K(ctrls, q); } - } - } - - // We want to test for conditional measurements which requires us to generate QIR with --runtime set to - // BasicMeasurementFeedback, which in turn doesn't allow updating mutables inside measurement conditionals. - // this means, we cannot easily get detailed failure information back from Q#, but the test driver can mock - // the simulator to track the point of failure. - operation TestFunctors() : Unit { - let qop = Qop(_, 1); - let adj_qop = Adjoint qop; - let ctl_qop = Controlled qop; - let adj_ctl_qop = Adjoint Controlled qop; - let ctl_ctl_qop = Controlled ctl_qop; - - use (q1, q2, q3) = (Qubit(), Qubit(), Qubit()) { - qop(q1); - if (M(q1) != One) { fail("error code: 1"); } - - adj_qop(q2); - if (M(q2) != One) { fail("error code: 2"); } - - ctl_qop([q1], q3); - if (M(q3) != One) { fail("error code: 3"); } - - adj_ctl_qop([q2], q3); - if (M(q3) != Zero) { fail("error code: 2"); } - - ctl_ctl_qop([q1], ([q2], q3)); - if (M(q3) != One) { fail("error code: 5"); } - - Controlled qop([q1, q2], q3); - if (M(q3) != Zero) { fail("error code: 6"); } - - use q4 = Qubit() { - Adjoint qop(q3); - Adjoint Controlled ctl_ctl_qop([q1], ([q2], ([q3], q4))); - if (M(q4) != One) { fail("error code: 7"); } - } - } - } - - // The operation is not sensical but in tests we can mock K operator to check that it actually executes - operation NoArgs() : Unit - is Adj+Ctl { - body (...) { - use q = Qubit(); - K(q); - } - adjoint self; - controlled (ctrls, ...) { - use q = Qubit(); - Controlled K(ctrls, q); - } - } - - operation TestFunctorsNoArgs() : Unit { - NoArgs(); - let qop = NoArgs; - let adj_qop = Adjoint qop; - let ctl_qop = Controlled qop; - let adj_ctl_qop = Adjoint Controlled qop; - let ctl_ctl_qop = Controlled ctl_qop; - - use (q1, q2, q3) = (Qubit(), Qubit(), Qubit()) { - X(q1); - X(q2); - X(q3); - - qop(); - adj_qop(); - ctl_qop([q1], ()); - adj_ctl_qop([q1], ()); - ctl_ctl_qop([q1], ([q2], ())); - - Controlled qop([q1, q2], ()); - Adjoint Controlled ctl_ctl_qop([q1], ([q2], ([q3], ()))); - } - } +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +// For the test to pass implement K to be the same as X. We need it for the test, because the standard bridge doesn't +// support multi-controlled X. +namespace Microsoft.Quantum.Intrinsic { + open Microsoft.Quantum.Core; + @Inline() + operation K(q : Qubit) : Unit + is Adj+Ctl { + body intrinsic; + adjoint self; + controlled intrinsic; + } +} + +namespace Microsoft.Quantum.Testing.QIR { + open Microsoft.Quantum.Intrinsic; + + operation Qop(q : Qubit, n : Int) : Unit + is Adj+Ctl { + body (...) { + if n%2 == 1 { K(q); } + } + adjoint self; + controlled (ctrls, ...) { + if n%2 == 1 { Controlled K(ctrls, q); } + } + } + + // We want to test for conditional measurements which requires us to generate QIR with --runtime set to + // BasicMeasurementFeedback, which in turn doesn't allow updating mutables inside measurement conditionals. + // this means, we cannot easily get detailed failure information back from Q#, but the test driver can mock + // the simulator to track the point of failure. + operation TestFunctors() : Unit { + let qop = Qop(_, 1); + let adj_qop = Adjoint qop; + let ctl_qop = Controlled qop; + let adj_ctl_qop = Adjoint Controlled qop; + let ctl_ctl_qop = Controlled ctl_qop; + + use (q1, q2, q3) = (Qubit(), Qubit(), Qubit()) { + qop(q1); + if (M(q1) != One) { fail("error code: 1"); } + + adj_qop(q2); + if (M(q2) != One) { fail("error code: 2"); } + + ctl_qop([q1], q3); + if (M(q3) != One) { fail("error code: 3"); } + + adj_ctl_qop([q2], q3); + if (M(q3) != Zero) { fail("error code: 2"); } + + ctl_ctl_qop([q1], ([q2], q3)); + if (M(q3) != One) { fail("error code: 5"); } + + Controlled qop([q1, q2], q3); + if (M(q3) != Zero) { fail("error code: 6"); } + + use q4 = Qubit() { + Adjoint qop(q3); + Adjoint Controlled ctl_ctl_qop([q1], ([q2], ([q3], q4))); + if (M(q4) != One) { fail("error code: 7"); } + } + } + } + + // The operation is not sensical but in tests we can mock K operator to check that it actually executes + operation NoArgs() : Unit + is Adj+Ctl { + body (...) { + use q = Qubit(); + K(q); + } + adjoint self; + controlled (ctrls, ...) { + use q = Qubit(); + Controlled K(ctrls, q); + } + } + + operation TestFunctorsNoArgs() : Unit { + NoArgs(); + let qop = NoArgs; + let adj_qop = Adjoint qop; + let ctl_qop = Controlled qop; + let adj_ctl_qop = Adjoint Controlled qop; + let ctl_ctl_qop = Controlled ctl_qop; + + use (q1, q2, q3) = (Qubit(), Qubit(), Qubit()) { + X(q1); + X(q2); + X(q3); + + qop(); + adj_qop(); + ctl_qop([q1], ()); + adj_ctl_qop([q1], ()); + ctl_ctl_qop([q1], ([q2], ())); + + Controlled qop([q1, q2], ()); + Adjoint Controlled ctl_ctl_qop([q1], ([q2], ([q3], ()))); + } + } } \ No newline at end of file diff --git a/src/QirRuntime/test/QIR-static/qsharp/qir-test-math.qs b/src/Qir/Tests/QIR-static/qsharp/qir-test-math.qs similarity index 99% rename from src/QirRuntime/test/QIR-static/qsharp/qir-test-math.qs rename to src/Qir/Tests/QIR-static/qsharp/qir-test-math.qs index 137718d76cd..1556fe939ba 100644 --- a/src/QirRuntime/test/QIR-static/qsharp/qir-test-math.qs +++ b/src/Qir/Tests/QIR-static/qsharp/qir-test-math.qs @@ -66,6 +66,10 @@ namespace Microsoft.Quantum.Testing.QIR.Math { return DrawRandomInt(min, max); } + operation TestDrawRandomDouble(min : Double, max : Double) : Double { + return DrawRandomDouble(min, max); + } + function Close(expected : Double, actual : Double) : Bool { let neighbourhood = 0.0000001; // On x86-64 + Win the error is in 16th digit after the decimal point. // E.g. enstead of 0.0 there can be 0.00000000000000012. diff --git a/src/QirRuntime/test/QIR-static/qsharp/qir-test-other.qs b/src/Qir/Tests/QIR-static/qsharp/qir-test-other.qs similarity index 100% rename from src/QirRuntime/test/QIR-static/qsharp/qir-test-other.qs rename to src/Qir/Tests/QIR-static/qsharp/qir-test-other.qs diff --git a/src/QirRuntime/test/QIR-static/qsharp/qir-test-output.qs b/src/Qir/Tests/QIR-static/qsharp/qir-test-output.qs similarity index 100% rename from src/QirRuntime/test/QIR-static/qsharp/qir-test-output.qs rename to src/Qir/Tests/QIR-static/qsharp/qir-test-output.qs diff --git a/src/QirRuntime/test/QIR-static/qsharp/qir-test-partials.qs b/src/Qir/Tests/QIR-static/qsharp/qir-test-partials.qs similarity index 96% rename from src/QirRuntime/test/QIR-static/qsharp/qir-test-partials.qs rename to src/Qir/Tests/QIR-static/qsharp/qir-test-partials.qs index 05e63538699..21659197b8a 100644 --- a/src/QirRuntime/test/QIR-static/qsharp/qir-test-partials.qs +++ b/src/Qir/Tests/QIR-static/qsharp/qir-test-partials.qs @@ -1,13 +1,13 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -namespace Microsoft.Quantum.Testing.QIR { - function Subtract(from : Int, what : Int) : Int { - return from - what; - } - - function TestPartials(x : Int, y : Int) : Int { - let subtractor = Subtract(x, _); - return subtractor(y); - } -} +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Testing.QIR { + function Subtract(from : Int, what : Int) : Int { + return from - what; + } + + function TestPartials(x : Int, y : Int) : Int { + let subtractor = Subtract(x, _); + return subtractor(y); + } +} diff --git a/src/QirRuntime/test/QIR-static/qsharp/qir-test-qubits-results.qs b/src/Qir/Tests/QIR-static/qsharp/qir-test-qubits-results.qs similarity index 97% rename from src/QirRuntime/test/QIR-static/qsharp/qir-test-qubits-results.qs rename to src/Qir/Tests/QIR-static/qsharp/qir-test-qubits-results.qs index dc6c74fb9ee..83ef174d76c 100644 --- a/src/QirRuntime/test/QIR-static/qsharp/qir-test-qubits-results.qs +++ b/src/Qir/Tests/QIR-static/qsharp/qir-test-qubits-results.qs @@ -1,18 +1,18 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. -namespace Microsoft.Quantum.Testing.QIR { - open Microsoft.Quantum.Intrinsic; - - operation TestQubitResultManagement() : Unit { - // exercise __quantum__rt__qubit_allocate_array - use qs = Qubit[2] { - X(qs[1]); - // exercise __quantum__rt__qubit_allocate - use q = Qubit() { - // exercise __quantum__rt__result_equal and accessing result constants - if (M(qs[1]) == One) { X(q); } - if (M(qs[0]) == M(q)) { fail("Unexpected measurement result"); } - } // exercise __quantum__rt__qubit_release - } // exercise __quantum__rt__qubit_release_array - } +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +namespace Microsoft.Quantum.Testing.QIR { + open Microsoft.Quantum.Intrinsic; + + operation TestQubitResultManagement() : Unit { + // exercise __quantum__rt__qubit_allocate_array + use qs = Qubit[2] { + X(qs[1]); + // exercise __quantum__rt__qubit_allocate + use q = Qubit() { + // exercise __quantum__rt__result_equal and accessing result constants + if (M(qs[1]) == One) { X(q); } + if (M(qs[0]) == M(q)) { fail("Unexpected measurement result"); } + } // exercise __quantum__rt__qubit_release + } // exercise __quantum__rt__qubit_release_array + } } \ No newline at end of file diff --git a/src/QirRuntime/test/QIR-static/qsharp/qir-test-strings.qs b/src/Qir/Tests/QIR-static/qsharp/qir-test-strings.qs similarity index 100% rename from src/QirRuntime/test/QIR-static/qsharp/qir-test-strings.qs rename to src/Qir/Tests/QIR-static/qsharp/qir-test-strings.qs diff --git a/src/Qir/Tests/QIR-tracer/CMakeLists.txt b/src/Qir/Tests/QIR-tracer/CMakeLists.txt new file mode 100644 index 00000000000..50fd5dc0073 --- /dev/null +++ b/src/Qir/Tests/QIR-tracer/CMakeLists.txt @@ -0,0 +1,30 @@ +set(TEST_FILES + qsharp/qir/tracer-qir.ll +) + +#============================================================================== +# The executable target for QIR tests triggers the custom actions to compile ll files +# +add_executable(qir-tracer-tests + qir-tracer-driver.cpp + tracer-config.cpp +) + +foreach(file ${TEST_FILES}) + target_source_from_qir(qir-tracer-tests ${file}) +endforeach() + +target_link_libraries(qir-tracer-tests PUBLIC + "-L${runtime_lib_path}" + -lMicrosoft.Quantum.Qir.Runtime + -lMicrosoft.Quantum.Qir.Tracer +) + +target_include_directories(qir-tracer-tests PUBLIC + ${test_includes} + ${public_includes} + "${PROJECT_SOURCE_DIR}/../Runtime/lib/Tracer" # TODO: Remove this when tracer api is put into public headers. +) + +install(TARGETS qir-tracer-tests RUNTIME DESTINATION "${CMAKE_BINARY_DIR}/bin") +add_unit_test(qir-tracer-tests) diff --git a/src/QirRuntime/test/QIR-tracer/generate.py b/src/Qir/Tests/QIR-tracer/generate.py similarity index 97% rename from src/QirRuntime/test/QIR-tracer/generate.py rename to src/Qir/Tests/QIR-tracer/generate.py index 473535416f9..20354e3da9a 100644 --- a/src/QirRuntime/test/QIR-tracer/generate.py +++ b/src/Qir/Tests/QIR-tracer/generate.py @@ -1,46 +1,46 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -import sys, os, platform, subprocess, datetime, shutil - -# ============================================================================= -# Generates QIR files for all *.qs files in this folder -# Accepts arguments: -# path to qsc.exe (absolute or rely on Path env) -# -# For example: "generate.py qsc.exe" or "generate.py c:\qsharp-compiler\qsc.exe" -# ============================================================================= - -# ============================================================================= -def log(message): - now = datetime.datetime.now() - current_time = now.strftime("%H:%M:%S") - print(current_time + ": " + message) -# ============================================================================= - -if __name__ == '__main__': - # this script is executed as script - root_dir = os.path.dirname(os.path.abspath(__file__)) - - # parameters - qsc = sys.argv[1] # argv[0] is the name of this script file - - # find all qs files in this folder - files_to_process = "" - output_file = "tracer-qir" - for file in os.listdir(root_dir): - (file_name, ext) = os.path.splitext(file) - if ext == ".qs": - files_to_process = files_to_process + " " + file - - # Compile as a lib so all functions are retained and don't have to workaround the current limitations of - # @EntryPoint attribute. - command = (qsc + " build --qir qir --input " + files_to_process + " --proj " + output_file) - log("Executing: " + command) - subprocess.run(command, shell = True) - - # copy the generated file into tracer's input files - generated_file = os.path.join(root_dir, "qir", output_file) + ".ll" - build_input_file = os.path.join(root_dir, output_file) + ".ll" - shutil.copyfile(generated_file, build_input_file) - +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +import sys, os, platform, subprocess, datetime, shutil + +# ============================================================================= +# Generates QIR files for all *.qs files in this folder +# Accepts arguments: +# path to qsc.exe (absolute or rely on Path env) +# +# For example: "generate.py qsc.exe" or "generate.py c:\qsharp-compiler\qsc.exe" +# ============================================================================= + +# ============================================================================= +def log(message): + now = datetime.datetime.now() + current_time = now.strftime("%H:%M:%S") + print(current_time + ": " + message) +# ============================================================================= + +if __name__ == '__main__': + # this script is executed as script + root_dir = os.path.dirname(os.path.abspath(__file__)) + + # parameters + qsc = sys.argv[1] # argv[0] is the name of this script file + + # find all qs files in this folder + files_to_process = "" + output_file = "tracer-qir" + for file in os.listdir(root_dir): + (file_name, ext) = os.path.splitext(file) + if ext == ".qs": + files_to_process = files_to_process + " " + file + + # Compile as a lib so all functions are retained and don't have to workaround the current limitations of + # @EntryPoint attribute. + command = (qsc + " build --qir qir --input " + files_to_process + " --proj " + output_file) + log("Executing: " + command) + subprocess.run(command, shell = True) + + # copy the generated file into tracer's input files + generated_file = os.path.join(root_dir, "qir", output_file) + ".ll" + build_input_file = os.path.join(root_dir, output_file) + ".ll" + shutil.copyfile(generated_file, build_input_file) + diff --git a/src/QirRuntime/test/QIR-tracer/qir-tracer-driver.cpp b/src/Qir/Tests/QIR-tracer/qir-tracer-driver.cpp similarity index 88% rename from src/QirRuntime/test/QIR-tracer/qir-tracer-driver.cpp rename to src/Qir/Tests/QIR-tracer/qir-tracer-driver.cpp index 09199fe5782..1914b666ba6 100644 --- a/src/QirRuntime/test/QIR-tracer/qir-tracer-driver.cpp +++ b/src/Qir/Tests/QIR-tracer/qir-tracer-driver.cpp @@ -1,49 +1,49 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -#include -#include - -#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file -#include "catch.hpp" - -#include "QirContext.hpp" -#include "tracer-config.hpp" -#include "tracer.hpp" - -using namespace std; -using namespace Microsoft::Quantum; - -namespace TracerUser -{ - -TEST_CASE("Invoke each intrinsic from Q# core once", "[qir-tracer]") -{ - shared_ptr tr = CreateTracer(1 /*layer duration*/, g_operationNames); - QirContextScope qirctx(tr.get(), false /*trackAllocatedObjects*/); - - REQUIRE_NOTHROW(Microsoft__Quantum__Testing__Tracer__TestCoreIntrinsics__body()); - const vector& layers = tr->UseLayers(); - - std::stringstream out; - tr->PrintLayerMetrics(out, ",", true /*printZeroMetrics*/); - INFO(out.str()); - - // TestCoreIntrinsics happens to produce 24 layers right now and we are not checking whether that's expected -- as - // testing of layering logic is better done by unit tests. - CHECK(layers.size() == 24); -} - -TEST_CASE("Conditional execution on measurement result", "[qir-tracer]") -{ - shared_ptr tr = CreateTracer(1 /*layer duration*/, g_operationNames); - QirContextScope qirctx(tr.get(), false /*trackAllocatedObjects*/); - - REQUIRE_NOTHROW(Microsoft__Quantum__Testing__Tracer__TestMeasurements__body()); - - std::stringstream out; - tr->PrintLayerMetrics(out, ",", true /*printZeroMetrics*/); - INFO(out.str()); - CHECK(tr->UseLayers().size() == 5); -} +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include +#include + +#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file +#include "catch.hpp" + +#include "QirContext.hpp" +#include "tracer-config.hpp" +#include "tracer.hpp" + +using namespace std; +using namespace Microsoft::Quantum; + +namespace TracerUser +{ + +TEST_CASE("Invoke each intrinsic from Q# core once", "[qir-tracer]") +{ + shared_ptr tr = CreateTracer(1 /*layer duration*/, g_operationNames); + QirContextScope qirctx(tr.get(), true /*trackAllocatedObjects*/); + + REQUIRE_NOTHROW(Microsoft__Quantum__Testing__Tracer__TestCoreIntrinsics__body()); + const vector& layers = tr->UseLayers(); + + std::stringstream out; + tr->PrintLayerMetrics(out, ",", true /*printZeroMetrics*/); + INFO(out.str()); + + // TestCoreIntrinsics happens to produce 24 layers right now and we are not checking whether that's expected -- as + // testing of layering logic is better done by unit tests. + CHECK(layers.size() == 24); +} + +TEST_CASE("Conditional execution on measurement result", "[qir-tracer]") +{ + shared_ptr tr = CreateTracer(1 /*layer duration*/, g_operationNames); + QirContextScope qirctx(tr.get(), true /*trackAllocatedObjects*/); + + REQUIRE_NOTHROW(Microsoft__Quantum__Testing__Tracer__TestMeasurements__body()); + + std::stringstream out; + tr->PrintLayerMetrics(out, ",", true /*printZeroMetrics*/); + INFO(out.str()); + CHECK(tr->UseLayers().size() == 5); +} } // namespace TracerUser \ No newline at end of file diff --git a/src/QirRuntime/test/QIR-tracer/tracer-conditionals.qs b/src/Qir/Tests/QIR-tracer/qsharp/tracer-conditionals.qs similarity index 97% rename from src/QirRuntime/test/QIR-tracer/tracer-conditionals.qs rename to src/Qir/Tests/QIR-tracer/qsharp/tracer-conditionals.qs index e9c0c512421..718808a2a3b 100644 --- a/src/QirRuntime/test/QIR-tracer/tracer-conditionals.qs +++ b/src/Qir/Tests/QIR-tracer/qsharp/tracer-conditionals.qs @@ -1,25 +1,25 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -namespace Microsoft.Quantum.Testing.Tracer { - open Microsoft.Quantum.Intrinsic; - - // Private helper operations. - operation Delay(op : (Qubit => Unit), arg : Qubit, aux : Unit) : Unit { - op(arg); - } - - operation TestMeasurements() : Unit { - use qs = Qubit[6]; - T(qs[0]); // layer 0 - let r0 = M(qs[0]); // layer 1 - T(qs[1]); // layer 0 - CNOT(qs[1], qs[2]); // layer 1 - let qs12 = [qs[1], qs[2]]; - let r12 = Measure([PauliY, PauliX], qs12); // layer 2 - - ApplyIfElseIntrinsic(r0, Delay(X, qs[3], _), Delay(Y, qs[3], _)); // layers 2, 3 - ApplyIfElseIntrinsic(r12, Delay(Z, qs[4], _), Delay(S, qs[4], _)); // layer 3, 4 - Rx(4.2, qs[5]); // layer 0 - } +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Testing.Tracer { + open Microsoft.Quantum.Intrinsic; + + // Private helper operations. + operation Delay(op : (Qubit => Unit), arg : Qubit, aux : Unit) : Unit { + op(arg); + } + + operation TestMeasurements() : Unit { + use qs = Qubit[6]; + T(qs[0]); // layer 0 + let r0 = M(qs[0]); // layer 1 + T(qs[1]); // layer 0 + CNOT(qs[1], qs[2]); // layer 1 + let qs12 = [qs[1], qs[2]]; + let r12 = Measure([PauliY, PauliX], qs12); // layer 2 + + ApplyIfElseIntrinsic(r0, Delay(X, qs[3], _), Delay(Y, qs[3], _)); // layers 2, 3 + ApplyIfElseIntrinsic(r12, Delay(Z, qs[4], _), Delay(S, qs[4], _)); // layer 3, 4 + Rx(4.2, qs[5]); // layer 0 + } } \ No newline at end of file diff --git a/src/QirRuntime/test/QIR-tracer/tracer-core.qs b/src/Qir/Tests/QIR-tracer/qsharp/tracer-core.qs similarity index 100% rename from src/QirRuntime/test/QIR-tracer/tracer-core.qs rename to src/Qir/Tests/QIR-tracer/qsharp/tracer-core.qs diff --git a/src/QirRuntime/test/QIR-tracer/tracer-intrinsics.qs b/src/Qir/Tests/QIR-tracer/qsharp/tracer-intrinsics.qs similarity index 100% rename from src/QirRuntime/test/QIR-tracer/tracer-intrinsics.qs rename to src/Qir/Tests/QIR-tracer/qsharp/tracer-intrinsics.qs diff --git a/src/QirRuntime/samples/StandaloneInputReference/qsharp/qir-standalone-input-reference.csproj b/src/Qir/Tests/QIR-tracer/qsharp/tracer-qir.csproj similarity index 62% rename from src/QirRuntime/samples/StandaloneInputReference/qsharp/qir-standalone-input-reference.csproj rename to src/Qir/Tests/QIR-tracer/qsharp/tracer-qir.csproj index dc30ec6b33f..28851db2b95 100644 --- a/src/QirRuntime/samples/StandaloneInputReference/qsharp/qir-standalone-input-reference.csproj +++ b/src/Qir/Tests/QIR-tracer/qsharp/tracer-qir.csproj @@ -1,9 +1,10 @@ - + Exe netcoreapp3.1 True + false diff --git a/src/QirRuntime/test/QIR-tracer/tracer-target.qs b/src/Qir/Tests/QIR-tracer/qsharp/tracer-target.qs similarity index 100% rename from src/QirRuntime/test/QIR-tracer/tracer-target.qs rename to src/Qir/Tests/QIR-tracer/qsharp/tracer-target.qs diff --git a/src/QirRuntime/test/QIR-tracer/tracer-config.cpp b/src/Qir/Tests/QIR-tracer/tracer-config.cpp similarity index 97% rename from src/QirRuntime/test/QIR-tracer/tracer-config.cpp rename to src/Qir/Tests/QIR-tracer/tracer-config.cpp index 2e58fd225dc..b23fdfb334d 100644 --- a/src/QirRuntime/test/QIR-tracer/tracer-config.cpp +++ b/src/Qir/Tests/QIR-tracer/tracer-config.cpp @@ -1,18 +1,18 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -// TODO: ideally, this file should be generated by the Q# compiler alongside the qir, using the mappings specified in -// target.qs. - -#include - -#include "QirRuntimeApi_I.hpp" -#include "tracer-config.hpp" - -namespace TracerUser -{ -const std::unordered_map g_operationNames = { - {0, "X"}, {1, "CX"}, {2, "MCX"}, {3, "Y"}, {4, "CY"}, {5, "MCY"}, {6, "Z"}, - {7, "CZ"}, {8, "MCZ"}, {19, "Rx"}, {20, "MCRx"}, {21, "Ry"}, {22, "MCRy"}, {23, "Rz"}, - {24, "MCRz"}, {9, "H"}, {10, "MCH"}, {11, "T"}, {12, "MCT"}, {15, "S"}, {16, "MCS"} /*etc.*/}; -} +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +// TODO: ideally, this file should be generated by the Q# compiler alongside the qir, using the mappings specified in +// target.qs. + +#include + +#include "QirRuntimeApi_I.hpp" +#include "tracer-config.hpp" + +namespace TracerUser +{ +const std::unordered_map g_operationNames = { + {0, "X"}, {1, "CX"}, {2, "MCX"}, {3, "Y"}, {4, "CY"}, {5, "MCY"}, {6, "Z"}, + {7, "CZ"}, {8, "MCZ"}, {19, "Rx"}, {20, "MCRx"}, {21, "Ry"}, {22, "MCRy"}, {23, "Rz"}, + {24, "MCRz"}, {9, "H"}, {10, "MCH"}, {11, "T"}, {12, "MCT"}, {15, "S"}, {16, "MCS"} /*etc.*/}; +} diff --git a/src/QirRuntime/test/QIR-tracer/tracer-config.hpp b/src/Qir/Tests/QIR-tracer/tracer-config.hpp similarity index 96% rename from src/QirRuntime/test/QIR-tracer/tracer-config.hpp rename to src/Qir/Tests/QIR-tracer/tracer-config.hpp index ac7eef038d3..c8327411f3d 100644 --- a/src/QirRuntime/test/QIR-tracer/tracer-config.hpp +++ b/src/Qir/Tests/QIR-tracer/tracer-config.hpp @@ -1,20 +1,20 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -// TODO: ideally, this file should be generated by the Q# compiler alongside the qir - -#pragma once - -#include -#include - -#include "TracerTypes.hpp" - -namespace TracerUser -{ -extern const std::unordered_map g_operationNames; -} // namespace TracerUser - -// Available function in generated QIR -extern "C" void Microsoft__Quantum__Testing__Tracer__TestCoreIntrinsics__body(); // NOLINT -extern "C" void Microsoft__Quantum__Testing__Tracer__TestMeasurements__body(); // NOLINT +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +// TODO: ideally, this file should be generated by the Q# compiler alongside the qir + +#pragma once + +#include +#include + +#include "TracerTypes.hpp" + +namespace TracerUser +{ +extern const std::unordered_map g_operationNames; +} // namespace TracerUser + +// Available function in generated QIR +extern "C" void Microsoft__Quantum__Testing__Tracer__TestCoreIntrinsics__body(); // NOLINT +extern "C" void Microsoft__Quantum__Testing__Tracer__TestMeasurements__body(); // NOLINT diff --git a/src/Qir/Tests/build-qir-tests.ps1 b/src/Qir/Tests/build-qir-tests.ps1 new file mode 100644 index 00000000000..48383f3df5a --- /dev/null +++ b/src/Qir/Tests/build-qir-tests.ps1 @@ -0,0 +1,21 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +[CmdletBinding()] +param ( + [Parameter()] + [Switch] + $SkipQSharpBuild +) + +. (Join-Path $PSScriptRoot .. qir-utils.ps1) + +Write-Host "##[info]Compile Q# Projects into QIR" +Build-QirProject (Join-Path $PSScriptRoot QIR-static qsharp) -SkipQSharpBuild:$SkipQSharpBuild +Build-QirProject (Join-Path $PSScriptRoot QIR-dynamic qsharp) -SkipQSharpBuild:$SkipQSharpBuild +Build-QirProject (Join-Path $PSScriptRoot QIR-tracer qsharp) -SkipQSharpBuild:$SkipQSharpBuild +Build-QirProject (Join-Path $PSScriptRoot FullstateSimulator qsharp) -SkipQSharpBuild:$SkipQSharpBuild + +if (-not (Build-CMakeProject $PSScriptRoot "QIR Tests")) { + throw "At least one project failed to compile. Check the logs." +} \ No newline at end of file diff --git a/src/Qir/Tests/test-qir-tests.ps1 b/src/Qir/Tests/test-qir-tests.ps1 new file mode 100644 index 00000000000..72302788343 --- /dev/null +++ b/src/Qir/Tests/test-qir-tests.ps1 @@ -0,0 +1,8 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +. (Join-Path $PSScriptRoot .. qir-utils.ps1) + +if (-not (Test-CTest (Join-Path $PSScriptRoot build $Env:BUILD_CONFIGURATION) "QIR Tests")) { + throw "At least one project failed testing. Check the logs." +} diff --git a/src/Qir/qir-utils.ps1 b/src/Qir/qir-utils.ps1 new file mode 100644 index 00000000000..38ae05e0724 --- /dev/null +++ b/src/Qir/qir-utils.ps1 @@ -0,0 +1,132 @@ +& (Join-Path $PSScriptRoot .. .. build set-env.ps1) + +function Build-QirProject { + param ( + [string] + $FolderPath, + + [Switch] + $SkipQSharpBuild + ) + + if (!$SkipQSharpBuild) { + Write-Host "##[info]Build Q# project for $Name '$FolderPath'" + dotnet build $FolderPath -c $Env:BUILD_CONFIGURATION -v $Env:BUILD_VERBOSITY + if ($LastExitCode -ne 0) { + Write-Host "##vso[task.logissue type=error;]Failed to compile Q# project at '$FolderPath' into QIR." + throw "Failed to compile Q# project at '$FolderPath' into QIR." + } + } +} + +function Build-CMakeProject { + [CmdletBinding()] + param ( + [Parameter()] + [String] + $Path, + + [Parameter()] + [String] + $Name + ) + + Write-Host "##[info]Build $Name" + $oldCC = $env:CC + $oldCXX = $env:CXX + $oldRC = $env:RC + + $clangTidy = "" + + if (($IsMacOS) -or ((Test-Path Env:AGENT_OS) -and ($Env:AGENT_OS.StartsWith("Darwin")))) + { + Write-Host "On MacOS build $Name using the default C/C++ compiler (should be AppleClang)" + } + elseif (($IsLinux) -or ((Test-Path Env:AGENT_OS) -and ($Env:AGENT_OS.StartsWith("Lin")))) + { + Write-Host "On Linux build $Name using Clang" + $env:CC = "clang-11" + $env:CXX = "clang++-11" + $env:RC = "clang++-11" + $clangTidy = "-DCMAKE_CXX_CLANG_TIDY=clang-tidy-11" + } + elseif (($IsWindows) -or ((Test-Path Env:AGENT_OS) -and ($Env:AGENT_OS.StartsWith("Win")))) + { + Write-Host "On Windows build $Name using Clang" + $env:CC = "clang.exe" + $env:CXX = "clang++.exe" + $env:RC = "clang++.exe" + + if (!(Get-Command clang -ErrorAction SilentlyContinue) -and (choco find --idonly -l llvm) -contains "llvm") { + # LLVM was installed by Chocolatey, so add the install location to the path. + $env:PATH += ";$($env:SystemDrive)\Program Files\LLVM\bin" + } + + if (Get-Command clang-tidy -ErrorAction SilentlyContinue) { + # Only run clang-tidy if it's installed. This is because the package used by chocolatey on + # the build pipeline doesn't include clang-tidy, so we allow skipping that there and let + # the Linux build catch tidy issues. + $clangTidy = "-DCMAKE_CXX_CLANG_TIDY=clang-tidy" + } + } else { + Write-Host "##vso[task.logissue type=warning;]Failed to identify the OS. Will use default CXX compiler" + } + + $cmakeBuildFolder = (Join-Path $Path build $Env:BUILD_CONFIGURATION) + if (-not (Test-Path $cmakeBuildFolder)) { + New-Item -Path $cmakeBuildFolder -ItemType "directory" + } + + $all_ok = $true + + Push-Location $cmakeBuildFolder + + cmake -G Ninja $clangTidy -D CMAKE_BUILD_TYPE="$Env:BUILD_CONFIGURATION" ../.. | Write-Host + if ($LastExitCode -ne 0) { + Write-Host "##vso[task.logissue type=error;]Failed to generate $Name." + $all_ok = $false + } else { + cmake --build . --target install | Write-Host + if ($LastExitCode -ne 0) { + Write-Host "##vso[task.logissue type=error;]Failed to build $Name." + $all_ok = $false + } + } + + Pop-Location + + $env:CC = $oldCC + $env:CXX = $oldCXX + $env:RC = $oldRC + + return $all_ok +} + +function Test-CTest { + [CmdletBinding()] + param ( + [Parameter()] + [string] + $Path, + + [Parameter()] + [string] + $Name + ) + + Write-Host "##[info]Test $Name" + + $all_ok = $true + Push-Location $Path + + ctest --verbose | Write-Host + + if ($LastExitCode -ne 0) { + Write-Host "##vso[task.logissue type=error;]Failed to test $Name" + $all_ok = $False + } + + Pop-Location + + return $all_ok +} \ No newline at end of file diff --git a/src/QirRuntime/CMakeLists.txt b/src/QirRuntime/CMakeLists.txt deleted file mode 100644 index 06f29c7fe5c..00000000000 --- a/src/QirRuntime/CMakeLists.txt +++ /dev/null @@ -1,47 +0,0 @@ -cmake_minimum_required(VERSION 3.10) - -message(INFO "*** build config: ${CMAKE_BUILD_TYPE}") - -# set the project name and version -project(qirruntime) - -# specify the C++ standard, compiler and other tools -set(CMAKE_CXX_STANDARD 14) -set(CMAKE_CXX_STANDARD_REQUIRED True) - -set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG") - -if(WIN32) - if(CMAKE_BUILD_TYPE STREQUAL "Debug") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_DLL -D_MT -Xclang --dependent-lib=msvcrtd") - else() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_DLL -D_MT -Xclang --dependent-lib=msvcrt") - endif() -endif() - -# feel free to customize these flags for your local builds (don't check in) -set(CMAKE_VERBOSE_MAKEFILE ON) -set(CMAKE_EXPORT_COMPILE_COMMANDS ON) -#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-inline") - -list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") - -set(public_includes "${PROJECT_SOURCE_DIR}/public") - -include(qir_cmake_include) - -if (WIN32) - set(QIR_BRIDGE_UTILITY_LIB "${PROJECT_BINARY_DIR}/lib/QIR/bridge-rt-u.lib") - set(QSHARP_FOUNDATION_BRIDGE_QIS_UTILITY_LIB "${PROJECT_BINARY_DIR}/lib/QSharpFoundation/qsharp-foundation-qis-u.lib") - set(QSHARP_CORE_BRIDGE_QIS_UTILITY_LIB "${PROJECT_BINARY_DIR}/lib/QSharpCore/qsharp-core-qis-u.lib") - set(QIR_BRIDGE_TRACER_UTILITY_LIB "${PROJECT_BINARY_DIR}/lib/Tracer/tracer-bridge-u.lib") -else() - set(QIR_BRIDGE_UTILITY_LIB "${PROJECT_BINARY_DIR}/lib/QIR/libbridge-rt-u.a") - set(QSHARP_FOUNDATION_BRIDGE_QIS_UTILITY_LIB "${PROJECT_BINARY_DIR}/lib/QSharpFoundation/libqsharp-foundation-qis-u.a") - set(QSHARP_CORE_BRIDGE_QIS_UTILITY_LIB "${PROJECT_BINARY_DIR}/lib/QSharpCore/libqsharp-core-qis-u.a") - set(QIR_BRIDGE_TRACER_UTILITY_LIB "${PROJECT_BINARY_DIR}/lib/Tracer/libtracer-bridge-u.a") -endif() - -add_subdirectory(lib) -add_subdirectory(samples) -add_subdirectory(test) diff --git a/src/QirRuntime/build-qir-runtime.ps1 b/src/QirRuntime/build-qir-runtime.ps1 deleted file mode 100644 index f7e4388b884..00000000000 --- a/src/QirRuntime/build-qir-runtime.ps1 +++ /dev/null @@ -1,92 +0,0 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. - -& (Join-Path $PSScriptRoot .. .. build set-env.ps1) -Write-Host "##[info]Compile Q# Projects into QIR" -$qirStaticPath = Join-Path $PSScriptRoot test QIR-static qsharp -dotnet build $qirStaticPath -c $Env:BUILD_CONFIGURATION -v $Env:BUILD_VERBOSITY -if ($LastExitCode -ne 0) { - Write-Host "##vso[task.logissue type=error;]Failed to compile Q# project at '$qirStaticPath' into QIR." - return -} -Copy-Item -Path (Join-Path $qirStaticPath qir *.ll) -Destination (Split-Path $qirStaticPath -Parent) -# Also copy to drops so it ends up in build artifacts, for easier post-build debugging. -Copy-Item -Path (Join-Path $qirStaticPath qir *.ll) -Destination $Env:DROPS_DIR - -Write-Host "##[info]Build QIR Runtime" -$oldCC = $env:CC -$oldCXX = $env:CXX -$oldRC = $env:RC - -$clangTidy = "" - -if (($IsMacOS) -or ((Test-Path Env:AGENT_OS) -and ($Env:AGENT_OS.StartsWith("Darwin")))) -{ - Write-Host "On MacOS build QIR Runtime using the default C/C++ compiler (should be AppleClang)" -} -elseif (($IsLinux) -or ((Test-Path Env:AGENT_OS) -and ($Env:AGENT_OS.StartsWith("Lin")))) -{ - Write-Host "On Linux build QIR Runtime using Clang" - $env:CC = "clang-11" - $env:CXX = "clang++-11" - $env:RC = "clang++-11" - $clangTidy = "-DCMAKE_CXX_CLANG_TIDY=clang-tidy-11" -} -elseif (($IsWindows) -or ((Test-Path Env:AGENT_OS) -and ($Env:AGENT_OS.StartsWith("Win")))) -{ - Write-Host "On Windows build QIR Runtime using Clang" - $env:CC = "clang.exe" - $env:CXX = "clang++.exe" - $env:RC = "clang++.exe" - - if (!(Get-Command clang -ErrorAction SilentlyContinue) -and (choco find --idonly -l llvm) -contains "llvm") { - # LLVM was installed by Chocolatey, so add the install location to the path. - $env:PATH += ";$($env:SystemDrive)\Program Files\LLVM\bin" - } - - if (Get-Command clang-tidy -ErrorAction SilentlyContinue) { - # Only run clang-tidy if it's installed. This is because the package used by chocolatey on - # the build pipeline doesn't include clang-tidy, so we allow skipping that there and let - # the Linux build catch tidy issues. - $clangTidy = "-DCMAKE_CXX_CLANG_TIDY=clang-tidy" - } -} else { - Write-Host "##vso[task.logissue type=error;]Failed to identify the OS. Will use default CXX compiler" -} - -$qirRuntimeBuildFolder = (Join-Path $PSScriptRoot "build\$Env:BUILD_CONFIGURATION") -if (-not (Test-Path $qirRuntimeBuildFolder)) { - New-Item -Path $qirRuntimeBuildFolder -ItemType "directory" -} - -Push-Location $qirRuntimeBuildFolder - -cmake -G Ninja $clangTidy -D CMAKE_BUILD_TYPE="$Env:BUILD_CONFIGURATION" ../.. -if ($LastExitCode -ne 0) { - Write-Host "##vso[task.logissue type=error;]Failed to generate QIR Runtime." -} -cmake --build . --target install -if ($LastExitCode -ne 0) { - Write-Host "##vso[task.logissue type=error;]Failed to build QIR Runtime." -} - -$os = "win" -$pattern = @("*.dll", "*.lib") -if ($IsMacOS) { - $os = "osx" - $pattern = @("*.dylib") -} elseif ($IsLinux) { - $os = "linux" - $pattern = @("*.so") -} -$osQirDropFolder = Join-Path $Env:DROPS_DIR QIR $os -if (!(Test-Path $osQirDropFolder)) { - New-Item -Path $osQirDropFolder -ItemType "directory" -} -$pattern | Foreach-Object { Copy-Item (Join-Path . bin $_) $osQirDropFolder } - -Pop-Location - -$env:CC = $oldCC -$env:CXX = $oldCXX -$env:RC = $oldRC diff --git a/src/QirRuntime/build.py b/src/QirRuntime/build.py deleted file mode 100644 index 5b6c1646a19..00000000000 --- a/src/QirRuntime/build.py +++ /dev/null @@ -1,102 +0,0 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. - -import sys, os, platform, subprocess, datetime, shutil -import generateqir - -# ============================================================================= -# The script will create [root]\build\[OS]\[Debug|Release] folder for the output. -# -# Accepts arguments: -# make/nomake -# 'make' will limit action to producing make files only -# 'nomake' will skip make step and build using the current cmake cache -# if omitted will make and then build the project -# debug/release -# default: debug -# -# For example: "build.py nomake debug ir" or "build.py release" -# ============================================================================= - -# ============================================================================= -def log(message): - now = datetime.datetime.now() - current_time = now.strftime("%H:%M:%S") - print(current_time + ": " + message) -# ============================================================================= - -# ============================================================================= -def create_if_doesnot_exist(dir): - if not os.path.isdir(dir): - os.mkdir(dir) - -def create_folder_structure(start_dir, dirs): - new_dir = start_dir - for dir in dirs: - new_dir = os.path.join(new_dir, dir) - create_if_doesnot_exist(new_dir) - return new_dir -# ============================================================================= - -# ============================================================================= -def do_build(root_dir, should_make, should_build, flavor): - build_dir = create_folder_structure(root_dir, ["build", platform.system(), flavor]) - os.chdir(build_dir) - - flavorWithDebInfo = flavor - if flavor == "Release" : - flavorWithDebInfo = "RelWithDebInfo" - - clangTidy = "clang-tidy" - if platform.system() == "Linux" : - clangTidy = "clang-tidy-11" - - if should_make: - cmd = "cmake -G Ninja -DCMAKE_CXX_CLANG_TIDY=" + clangTidy + " -DCMAKE_BUILD_TYPE=" + flavorWithDebInfo + " ../../.." - log("running: " + cmd) - result = subprocess.run(cmd, shell = True) - if result.returncode != 0: - return result - - if should_build: - cmd = "cmake --build . --target install --config " + flavorWithDebInfo - log("running: " + cmd) - result = subprocess.run(cmd, shell = True) - - return result -# ============================================================================= - -if __name__ == '__main__': - # this script is executed as script - # parameters - flavor = "Debug" - should_make = True - should_build = True - noqirgen = False - - for arg in sys.argv: - arg = arg.lower() - if "build.py" in arg: - continue - elif arg == "debug": - flavor = "Debug" - elif arg == "release": - flavor = "Release" - elif arg == "nomake": - should_make = False - elif arg == "make": - should_build = False - elif arg == "noqirgen": - noqirgen = True - else: - log("unrecognized argument: " + arg) - sys.exit() - - root_dir = os.path.dirname(os.path.abspath(__file__)) - - if not noqirgen: - if generateqir.do_generate_all(root_dir) != 0: - log("Aborting build due to failures in QIR generation") - sys.exit() - - do_build(root_dir, should_make, should_build, flavor) \ No newline at end of file diff --git a/src/QirRuntime/cmake/qir_cmake_include.cmake b/src/QirRuntime/cmake/qir_cmake_include.cmake deleted file mode 100644 index 7328a745ee0..00000000000 --- a/src/QirRuntime/cmake/qir_cmake_include.cmake +++ /dev/null @@ -1,68 +0,0 @@ -#=============================================================================== -# compiling from IR -# -# CMake doesn't support LLVM IR files as sources so we compile them with custom -# commands, which produce UTILITY libs that can only be linked in using abs paths -# (rather than the target name): -# Target "qir_bridge_qis" of type UTILITY may not be linked into another -# target. One may link only to INTERFACE, OBJECT, STATIC or SHARED -# libraries, or to executables with the ENABLE_EXPORTS property set. -# -macro(compile_from_qir source_file target) - set(CLANG_ARGS "-c") - if (CMAKE_BUILD_TYPE STREQUAL "Debug") - set(CLANG_ARGS - "${CLANG_ARGS}" - "-O0" - "-D_DEBUG" - ) - endif() - - set(INFILE - "${CMAKE_CURRENT_SOURCE_DIR}/${source_file}.ll" - ) - set(OBJFILE - "${CMAKE_CURRENT_BINARY_DIR}/${source_file}.obj" - ) - - set(OBJFILE_COMPILE "${source_file}-compile") - add_custom_command(OUTPUT ${OBJFILE_COMPILE} - COMMAND ${CMAKE_CXX_COMPILER} - ARGS ${CLANG_ARGS} ${INFILE} "-o" ${OBJFILE} - DEPENDS ${INFILE} - BYPRODUCTS ${OBJFILE} - COMMENT "Compiling ${source_file}.ll" - VERBATIM - ) - - add_custom_target(${source_file}_compile DEPENDS ${OBJFILE_COMPILE}) - - if (WIN32) - set(QIR_UTILITY_LIB "${CMAKE_CURRENT_BINARY_DIR}/${source_file}-u.lib" ) - else() - set(QIR_UTILITY_LIB "${CMAKE_CURRENT_BINARY_DIR}/lib${source_file}-u.a") - endif() - - add_custom_command(OUTPUT ${QIR_UTILITY_LIB} - COMMAND ${CMAKE_AR} - ARGS "rc" ${QIR_UTILITY_LIB} ${OBJFILE} - DEPENDS ${source_file}_compile ${INFILE} - COMMENT "Creating a lib from ${source_file}.ll" - VERBATIM - ) - - if (NOT ${target} STREQUAL "") - add_custom_target(${target} DEPENDS ${QIR_UTILITY_LIB}) - endif() -endmacro(compile_from_qir) - -macro(target_source_from_qir_obj target_name source_file) - set_source_files_properties( - "${source_file}.obj" - PROPERTIES - EXTERNAL_OBJECT true - ) - target_sources(${target_name} PUBLIC - "${CMAKE_CURRENT_BINARY_DIR}/${source_file}.obj" - ) -endmacro() \ No newline at end of file diff --git a/src/QirRuntime/generateqir.py b/src/QirRuntime/generateqir.py deleted file mode 100644 index af013f67cb9..00000000000 --- a/src/QirRuntime/generateqir.py +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. - -import os, sys, subprocess, datetime, shutil, pathlib - -# ============================================================================= -def log(message): - now = datetime.datetime.now() - current_time = now.strftime("%H:%M:%S") - print(current_time + ": " + message) -# ============================================================================= - -# ============================================================================= -# The Q# project should be located in a subfolder under test_dir, named "qsharp" -def do_generate_qir(test_dir): - qsharp_project_path = os.path.join(test_dir, "qsharp") - qirgencmd = "dotnet build " + qsharp_project_path - log("running: " + qirgencmd) - result = subprocess.run(qirgencmd, shell = True) - if result.returncode != 0: - return result - - # really, expect to have only one file - for generated_qir_file in os.listdir(os.path.join(qsharp_project_path, "qir")): - shutil.copyfile( - os.path.join(os.path.join(qsharp_project_path, "qir", generated_qir_file)), - os.path.join(test_dir, generated_qir_file)) - - return result -# ============================================================================= - -# ============================================================================= -def do_generate_all(root_dir): - test_projects = [ - os.path.join(root_dir, "test", "QIR-static"), - os.path.join(root_dir, "samples", "StandaloneInputReference") - # add other test folders here - ] - - for test_dir in test_projects: - log("generating QIR for: " + test_dir) - result = do_generate_qir(test_dir) - if result.returncode != 0: - log("Failed to generate QIR for: " + test_dir) - return result.returncode - - return 0 -# ============================================================================= - -if __name__ == '__main__': - root_dir = os.path.dirname(os.path.abspath(__file__)) - do_generate_all(root_dir) - - diff --git a/src/QirRuntime/public/BitStates.hpp b/src/QirRuntime/public/BitStates.hpp deleted file mode 100644 index 671a5742e36..00000000000 --- a/src/QirRuntime/public/BitStates.hpp +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -#pragma once - -#include -#include - -#include "CoreTypes.hpp" - -namespace Microsoft -{ -namespace Quantum -{ - /*============================================================================== - Provides dynamically extendable storage for packed bits - ==============================================================================*/ - struct QIR_SHARED_API BitStates - { - typedef uint64_t TSLOT; - static constexpr int slotSizeBits = sizeof(TSLOT) * 8; - - std::vector slots; - - static long GetSlotIndex(long bitIndex) - { - return (bitIndex / (slotSizeBits)); - } - static long GetIndexInSlot(long bitIndex) - { - return (bitIndex & (slotSizeBits - 1)); - } - - void ExtendToInclude(long index) - { - long slotIndex = GetSlotIndex(index); - for (long i = this->slots.size(); i < slotIndex + 1; i++) - { - this->slots.push_back(0); - } - } - - void Clear() - { - this->slots.clear(); - } - - void SetBitAt(long index) - { - const long slotIndex = GetSlotIndex(index); - const long bitIndex = GetIndexInSlot(index); - this->slots[slotIndex] |= (static_cast(1) << bitIndex); - } - - void FlipBitAt(long index) - { - const long slotIndex = GetSlotIndex(index); - const long bitIndex = GetIndexInSlot(index); - this->slots[slotIndex] ^= (static_cast(1) << bitIndex); - } - - bool IsBitSetAt(long index) const - { - const long slotIndex = GetSlotIndex(index); - const long bitIndex = GetIndexInSlot(index); - return this->slots[slotIndex] & (static_cast(1) << bitIndex); - } - - bool IsAny() const - { - for (long i = 0; i < this->slots.size(); i++) - { - if (this->slots[i] != 0) - { - return true; - } - } - return false; - } - }; - -} // namespace Quantum -} // namespace Microsoft \ No newline at end of file diff --git a/src/QirRuntime/samples/CMakeLists.txt b/src/QirRuntime/samples/CMakeLists.txt deleted file mode 100644 index 247f423c7a8..00000000000 --- a/src/QirRuntime/samples/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -add_subdirectory(StandaloneInputReference) diff --git a/src/QirRuntime/samples/StandaloneInputReference/qir-standalone-input-reference.ll b/src/QirRuntime/samples/StandaloneInputReference/qir-standalone-input-reference.ll deleted file mode 100644 index d990f34df62..00000000000 --- a/src/QirRuntime/samples/StandaloneInputReference/qir-standalone-input-reference.ll +++ /dev/null @@ -1,77 +0,0 @@ - -%Result = type opaque -%Range = type { i64, i64, i64 } -%String = type opaque - -@ResultZero = external global %Result* -@ResultOne = external global %Result* -@PauliI = constant i2 0 -@PauliX = constant i2 1 -@PauliY = constant i2 -1 -@PauliZ = constant i2 -2 -@EmptyRange = internal constant %Range { i64 0, i64 1, i64 -1 } -@0 = internal constant [26 x i8] c"Exercise Supported Inputs\00" -@1 = internal constant [11 x i8] c"intValue: \00" -@2 = internal constant [14 x i8] c"doubleValue: \00" -@3 = internal constant [14 x i8] c"resultValue: \00" -@4 = internal constant [14 x i8] c"stringValue: \00" - -@Quantum__StandaloneSupportedInputs__ExerciseInputs = alias i64 (i64, double, %Result*, %String*), i64 (i64, double, %Result*, %String*)* @Quantum__StandaloneSupportedInputs__ExerciseInputs__body - -define i64 @Quantum__StandaloneSupportedInputs__ExerciseInputs__body(i64 %intValue, double %doubleValue, %Result* %resultValue, %String* %stringValue) #0 { -entry: - %msg = call %String* @__quantum__rt__string_create(i32 25, i8* getelementptr inbounds ([26 x i8], [26 x i8]* @0, i32 0, i32 0)) - call void @__quantum__qis__message__body(%String* %msg) - call void @__quantum__rt__string_update_reference_count(%String* %msg, i64 -1) - %0 = call %String* @__quantum__rt__string_create(i32 10, i8* getelementptr inbounds ([11 x i8], [11 x i8]* @1, i32 0, i32 0)) - %1 = call %String* @__quantum__rt__int_to_string(i64 %intValue) - %msg__1 = call %String* @__quantum__rt__string_concatenate(%String* %0, %String* %1) - call void @__quantum__rt__string_update_reference_count(%String* %0, i64 -1) - call void @__quantum__rt__string_update_reference_count(%String* %1, i64 -1) - call void @__quantum__qis__message__body(%String* %msg__1) - call void @__quantum__rt__string_update_reference_count(%String* %msg__1, i64 -1) - %2 = call %String* @__quantum__rt__string_create(i32 13, i8* getelementptr inbounds ([14 x i8], [14 x i8]* @2, i32 0, i32 0)) - %3 = call %String* @__quantum__rt__double_to_string(double %doubleValue) - %msg__2 = call %String* @__quantum__rt__string_concatenate(%String* %2, %String* %3) - call void @__quantum__rt__string_update_reference_count(%String* %2, i64 -1) - call void @__quantum__rt__string_update_reference_count(%String* %3, i64 -1) - call void @__quantum__qis__message__body(%String* %msg__2) - call void @__quantum__rt__string_update_reference_count(%String* %msg__2, i64 -1) - %4 = call %String* @__quantum__rt__string_create(i32 13, i8* getelementptr inbounds ([14 x i8], [14 x i8]* @3, i32 0, i32 0)) - %5 = call %String* @__quantum__rt__result_to_string(%Result* %resultValue) - %msg__3 = call %String* @__quantum__rt__string_concatenate(%String* %4, %String* %5) - call void @__quantum__rt__string_update_reference_count(%String* %4, i64 -1) - call void @__quantum__rt__string_update_reference_count(%String* %5, i64 -1) - call void @__quantum__qis__message__body(%String* %msg__3) - call void @__quantum__rt__string_update_reference_count(%String* %msg__3, i64 -1) - %6 = call %String* @__quantum__rt__string_create(i32 13, i8* getelementptr inbounds ([14 x i8], [14 x i8]* @4, i32 0, i32 0)) - call void @__quantum__rt__string_update_reference_count(%String* %stringValue, i64 1) - %msg__4 = call %String* @__quantum__rt__string_concatenate(%String* %6, %String* %stringValue) - call void @__quantum__rt__string_update_reference_count(%String* %6, i64 -1) - call void @__quantum__rt__string_update_reference_count(%String* %stringValue, i64 -1) - call void @__quantum__qis__message__body(%String* %msg__4) - call void @__quantum__rt__string_update_reference_count(%String* %msg__4, i64 -1) - ret i64 0 -} - -declare %String* @__quantum__rt__string_create(i32, i8*) - -declare void @__quantum__qis__message__body(%String*) - -declare void @__quantum__rt__string_update_reference_count(%String*, i64) - -declare %String* @__quantum__rt__int_to_string(i64) - -declare %String* @__quantum__rt__string_concatenate(%String*, %String*) - -declare %String* @__quantum__rt__double_to_string(double) - -declare %String* @__quantum__rt__result_to_string(%Result*) - -define void @Microsoft__Quantum__Intrinsic__Message__body(%String* %msg) { -entry: - call void @__quantum__qis__message__body(%String* %msg) - ret void -} - -attributes #0 = { "EntryPoint" } diff --git a/src/QirRuntime/samples/StandaloneInputReference/qsharp/qir-standalone-input-reference.qs b/src/QirRuntime/samples/StandaloneInputReference/qsharp/qir-standalone-input-reference.qs deleted file mode 100644 index 0d6223eadab..00000000000 --- a/src/QirRuntime/samples/StandaloneInputReference/qsharp/qir-standalone-input-reference.qs +++ /dev/null @@ -1,15 +0,0 @@ -namespace Quantum.StandaloneSupportedInputs { - - open Microsoft.Quantum.Canon; - open Microsoft.Quantum.Intrinsic; - - @EntryPoint() - operation ExerciseInputs (intValue : Int, doubleValue : Double, resultValue : Result, stringValue : String) : Int { - Message("Exercise Supported Inputs"); - Message($"intValue: {intValue}"); - Message($"doubleValue: {doubleValue}"); - Message($"resultValue: {resultValue}"); - Message($"stringValue: {stringValue}"); - return 0; - } -} diff --git a/src/QirRuntime/test-qir-runtime.ps1 b/src/QirRuntime/test-qir-runtime.ps1 deleted file mode 100644 index 0b0094e1054..00000000000 --- a/src/QirRuntime/test-qir-runtime.ps1 +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. - -Write-Host "##[info]Test QIR Runtime" - -Push-Location (Join-Path $PSScriptRoot build $Env:BUILD_CONFIGURATION test) - -ctest --verbose - -if ($LastExitCode -ne 0) { - Write-Host "##vso[task.logissue type=error;]Failed to test QIR Runtime" - $script:all_ok = $False -} - -Pop-Location - -Write-Host "##[info]Test QIR Standalone Sample" - -Push-Location (Join-Path $PSScriptRoot build $Env:BUILD_CONFIGURATION samples StandaloneInputReference) - -ctest --verbose - -if ($LastExitCode -ne 0) { - Write-Host "##vso[task.logissue type=error;]Failed to test QIR Standalone Sample" - $script:all_ok = $False -} - -Pop-Location diff --git a/src/QirRuntime/test.py b/src/QirRuntime/test.py deleted file mode 100644 index 2c6e1a8e701..00000000000 --- a/src/QirRuntime/test.py +++ /dev/null @@ -1,119 +0,0 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. - -import sys, os, platform, subprocess, datetime, shutil -import build, generateqir - -# ============================================================================= -# Accepts arguments: -# nobuild [if omitted, will attempt to build the project] -# noqirgen [if omitted, will attempt to generate qir from Q# projects] -# debug/release -# -# For example: "test.py nobuild debug" -# ============================================================================= - -# ============================================================================= -def log(message): - now = datetime.datetime.now() - current_time = now.strftime("%H:%M:%S") - print(current_time + ": " + message) -# ============================================================================= - -if __name__ == '__main__': - # this script is executed as script - root_dir = os.path.dirname(os.path.abspath(__file__)) - - # parameters - flavor = "Debug" - nobuild = False - noqirgen = False - for arg in sys.argv: - arg = arg.lower() - if arg == "test.py": - continue - elif arg == "debug": - flavor = "Debug" - elif arg == "release": - flavor = "Release" - elif arg == "nobuild": - nobuild = True - noqirgen = True - elif arg == "noqirgen": - noqirgen = True - else: - log("unrecognized argument: " + arg) - sys.exit() - - if not noqirgen: - if generateqir.do_generate_all(root_dir) != 0: - log("build failed to generate QIR => won't execute the tests") - log("to execute the tests from the last successful build run `test.py nobuild`") - sys.exit() - - if not nobuild: - result = build.do_build(root_dir, True, True, flavor) # should_make, should_build - if result.returncode != 0: - log("build failed with exit code {0} => won't execute the tests".format(result.returncode)) - log("to execute the tests from the last successful build run `test.py nobuild`") - sys.exit() - - install_dir = os.path.join(root_dir, "build", platform.system(), flavor, "bin") - if not os.path.isdir(install_dir): - log("please build first: 'build.py [debug|release] [ir]'") - sys.exit() - - print("\n") - - # Configure DLL lookup locations to include full state simulator and qdk - exe_ext = "" - fullstate_sim_dir = os.path.join(root_dir, "..", "Simulation", "Native", "build", flavor) - if platform.system() == "Windows": - exe_ext = ".exe" - os.environ['PATH'] = os.environ['PATH'] + ";" + fullstate_sim_dir + ";" + install_dir - else: - # add the folder to the list of locations to load libraries from - old = os.environ.get("LD_LIBRARY_PATH") - if old: - os.environ["LD_LIBRARY_PATH"] = old + ":" + fullstate_sim_dir + ":" + install_dir - else: - os.environ["LD_LIBRARY_PATH"] = fullstate_sim_dir + ":" + install_dir - - old = os.environ.get("DYLD_LIBRARY_PATH") - if old: - os.environ["DYLD_LIBRARY_PATH"] = old + ":" + fullstate_sim_dir + ":" + install_dir - else: - os.environ["DYLD_LIBRARY_PATH"] = fullstate_sim_dir + ":" + install_dir - - log("========= Running native tests =========") - test_binaries = [ - "fullstate-simulator-tests", - "qir-runtime-unittests", - "qir-static-tests", - "qir-dynamic-tests", - "qir-tracer-tests" - ] - - for name in test_binaries: - test_binary = os.path.join(install_dir, name + exe_ext) - log(test_binary) - subprocess.run(test_binary + " ~[skip]", shell = True) - - log("========= Running samples =========") - subprocess.run( - "qir-input-reference-standalone" +\ - " --int-value 1" +\ - " --integer-array 1 2 3 4 5" +\ - " --double-value 0.5" +\ - " --double-array 0.1 0.2 0.3 0.4 0.5" +\ - " --bool-value true" +\ - " --bool-array true TRUE false fALSe 0" +\ - " --pauli-value PauliX" +\ - " --pauli-array PauliI paulix PAULIY PAulIZ" +\ - " --range-value 1 2 10" +\ - " --range-array 1 2 10 5 5 50 10 1 20" +\ - " --string-value ASampleString" +\ - " --result-value one" +\ - " --result-array one ONE true TRUE 1 zero ZERO false FALSE 0") - - print("\n") diff --git a/src/QirRuntime/test/CMakeLists.txt b/src/QirRuntime/test/CMakeLists.txt deleted file mode 100644 index aaeee4ad5a7..00000000000 --- a/src/QirRuntime/test/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -include(unit_test_include) - -add_subdirectory(FullstateSimulator) -add_subdirectory(QIR-dynamic) -add_subdirectory(QIR-static) -add_subdirectory(QIR-tracer) -add_subdirectory(unittests) diff --git a/src/QirRuntime/test/FullstateSimulator/CMakeLists.txt b/src/QirRuntime/test/FullstateSimulator/CMakeLists.txt deleted file mode 100644 index 21c10647ba4..00000000000 --- a/src/QirRuntime/test/FullstateSimulator/CMakeLists.txt +++ /dev/null @@ -1,28 +0,0 @@ - -compile_from_qir(qir-test-simulator qir_test_simulator_target) - -add_executable(fullstate-simulator-tests - FullstateSimulatorTests.cpp) - -target_link_libraries(fullstate-simulator-tests PUBLIC - ${QIR_UTILITY_LIB} # created by compile_from_qir - ${QIR_BRIDGE_UTILITY_LIB} - ${QSHARP_FOUNDATION_BRIDGE_QIS_UTILITY_LIB} - ${QSHARP_CORE_BRIDGE_QIS_UTILITY_LIB} - qir-rt-support - qsharp-foundation-qis-support - qsharp-core-qis-support - simulators -) - -target_include_directories(fullstate-simulator-tests PUBLIC - "${test_includes}" - "${public_includes}" - "${PROJECT_SOURCE_DIR}/lib/QIR" -) -target_compile_definitions(fullstate-simulator-tests PRIVATE EXPORT_QIR_API) -add_dependencies(fullstate-simulator-tests qir_test_simulator_target) - -install(TARGETS fullstate-simulator-tests RUNTIME DESTINATION "${CMAKE_BINARY_DIR}/bin") -add_unit_test(fullstate-simulator-tests) - diff --git a/src/QirRuntime/test/FullstateSimulator/qir-test-simulator.ll b/src/QirRuntime/test/FullstateSimulator/qir-test-simulator.ll deleted file mode 100644 index dd0bebfe9a1..00000000000 --- a/src/QirRuntime/test/FullstateSimulator/qir-test-simulator.ll +++ /dev/null @@ -1,1398 +0,0 @@ - -%Result = type opaque -%Range = type { i64, i64, i64 } -%Tuple = type opaque -%Qubit = type opaque -%Array = type opaque -%Callable = type opaque - -@ResultZero = external global %Result* -@ResultOne = external global %Result* -@PauliI = constant i2 0 -@PauliX = constant i2 1 -@PauliY = constant i2 -1 -@PauliZ = constant i2 -2 -@EmptyRange = internal constant %Range { i64 0, i64 1, i64 -1 } -@Microsoft__Quantum__Intrinsic__X = constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__X__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__X__adj__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__X__ctl__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__X__ctladj__wrapper] -@Microsoft__Quantum__Intrinsic__Y = constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Y__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Y__adj__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Y__ctl__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Y__ctladj__wrapper] -@Microsoft__Quantum__Intrinsic__Z = constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Z__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Z__adj__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Z__ctl__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Z__ctladj__wrapper] -@Microsoft__Quantum__Intrinsic__H = constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__H__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__H__adj__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__H__ctl__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__H__ctladj__wrapper] -@Microsoft__Quantum__Intrinsic__S = constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__S__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__S__adj__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__S__ctl__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__S__ctladj__wrapper] -@Microsoft__Quantum__Intrinsic__T = constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__T__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__T__adj__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__T__ctl__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__T__ctladj__wrapper] -@Microsoft__Quantum__Intrinsic__R = constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__R__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__R__adj__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__R__ctl__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__R__ctladj__wrapper] -@PartialApplication__1 = constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Lifted__PartialApplication__1__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Lifted__PartialApplication__1__adj__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Lifted__PartialApplication__1__ctl__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Lifted__PartialApplication__1__ctladj__wrapper] -@MemoryManagement__1 = constant [2 x void (%Tuple*, i64)*] [void (%Tuple*, i64)* @MemoryManagement__1__RefCount, void (%Tuple*, i64)* @MemoryManagement__1__AliasCount] - -@Microsoft__Quantum__Testing__QIR__Test_Simulator_QIS = alias i64 (), i64 ()* @Microsoft__Quantum__Testing__QIR__Test_Simulator_QIS__body - -define void @Microsoft__Quantum__Intrinsic__X__body(%Qubit* %qb) { -entry: - call void @__quantum__qis__x__body(%Qubit* %qb) - ret void -} - -declare void @__quantum__qis__x__body(%Qubit*) - -define void @Microsoft__Quantum__Intrinsic__X__adj(%Qubit* %qb) { -entry: - call void @__quantum__qis__x__body(%Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__X__ctl(%Array* %__controlQubits__, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 1) - call void @__quantum__qis__x__ctl(%Array* %__controlQubits__, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 -1) - ret void -} - -declare void @__quantum__rt__array_update_alias_count(%Array*, i64) - -declare void @__quantum__qis__x__ctl(%Array*, %Qubit*) - -define void @Microsoft__Quantum__Intrinsic__X__ctladj(%Array* %__controlQubits__, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 1) - call void @__quantum__qis__x__ctl(%Array* %__controlQubits__, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 -1) - ret void -} - -define %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %qb) { -entry: - %bases__inline__1 = call %Array* @__quantum__rt__array_create_1d(i32 1, i64 1) - %0 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %bases__inline__1, i64 0) - %1 = bitcast i8* %0 to i2* - %2 = load i2, i2* @PauliZ - store i2 %2, i2* %1 - call void @__quantum__rt__array_update_alias_count(%Array* %bases__inline__1, i64 1) - %qubits__inline__1 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) - %3 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qubits__inline__1, i64 0) - %4 = bitcast i8* %3 to %Qubit** - store %Qubit* %qb, %Qubit** %4 - call void @__quantum__rt__array_update_alias_count(%Array* %qubits__inline__1, i64 1) - %5 = call %Result* @__quantum__qis__measure__body(%Array* %bases__inline__1, %Array* %qubits__inline__1) - call void @__quantum__rt__array_update_alias_count(%Array* %bases__inline__1, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits__inline__1, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %bases__inline__1, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %qubits__inline__1, i64 -1) - ret %Result* %5 -} - -declare %Array* @__quantum__rt__array_create_1d(i32, i64) - -declare i8* @__quantum__rt__array_get_element_ptr_1d(%Array*, i64) - -declare %Result* @__quantum__qis__measure__body(%Array*, %Array*) - -declare void @__quantum__rt__array_update_reference_count(%Array*, i64) - -define void @Microsoft__Quantum__Intrinsic__S__body(%Qubit* %qb) { -entry: - call void @__quantum__qis__s__body(%Qubit* %qb) - ret void -} - -declare void @__quantum__qis__s__body(%Qubit*) - -define void @Microsoft__Quantum__Intrinsic__S__adj(%Qubit* %qb) { -entry: - call void @__quantum__qis__s__adj(%Qubit* %qb) - ret void -} - -declare void @__quantum__qis__s__adj(%Qubit*) - -define void @Microsoft__Quantum__Intrinsic__S__ctl(%Array* %__controlQubits__, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 1) - call void @__quantum__qis__s__ctl(%Array* %__controlQubits__, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 -1) - ret void -} - -declare void @__quantum__qis__s__ctl(%Array*, %Qubit*) - -define void @Microsoft__Quantum__Intrinsic__S__ctladj(%Array* %__controlQubits__, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 1) - call void @__quantum__qis__s__ctladj(%Array* %__controlQubits__, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 -1) - ret void -} - -declare void @__quantum__qis__s__ctladj(%Array*, %Qubit*) - -define %Result* @Microsoft__Quantum__Intrinsic__Measure__body(%Array* %bases, %Array* %qubits) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %bases, i64 1) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 1) - %0 = call %Result* @__quantum__qis__measure__body(%Array* %bases, %Array* %qubits) - call void @__quantum__rt__array_update_alias_count(%Array* %bases, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 -1) - ret %Result* %0 -} - -define void @Microsoft__Quantum__Intrinsic__T__body(%Qubit* %qb) { -entry: - call void @__quantum__qis__t__body(%Qubit* %qb) - ret void -} - -declare void @__quantum__qis__t__body(%Qubit*) - -define void @Microsoft__Quantum__Intrinsic__T__adj(%Qubit* %qb) { -entry: - call void @__quantum__qis__t__adj(%Qubit* %qb) - ret void -} - -declare void @__quantum__qis__t__adj(%Qubit*) - -define void @Microsoft__Quantum__Intrinsic__T__ctl(%Array* %__controlQubits__, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 1) - call void @__quantum__qis__t__ctl(%Array* %__controlQubits__, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 -1) - ret void -} - -declare void @__quantum__qis__t__ctl(%Array*, %Qubit*) - -define void @Microsoft__Quantum__Intrinsic__T__ctladj(%Array* %__controlQubits__, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 1) - call void @__quantum__qis__t__ctladj(%Array* %__controlQubits__, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 -1) - ret void -} - -declare void @__quantum__qis__t__ctladj(%Array*, %Qubit*) - -define void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %qb) { -entry: - call void @__quantum__qis__h__body(%Qubit* %qb) - ret void -} - -declare void @__quantum__qis__h__body(%Qubit*) - -define void @Microsoft__Quantum__Intrinsic__H__adj(%Qubit* %qb) { -entry: - call void @__quantum__qis__h__body(%Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__H__ctl(%Array* %__controlQubits__, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 1) - call void @__quantum__qis__h__ctl(%Array* %__controlQubits__, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 -1) - ret void -} - -declare void @__quantum__qis__h__ctl(%Array*, %Qubit*) - -define void @Microsoft__Quantum__Intrinsic__H__ctladj(%Array* %__controlQubits__, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 1) - call void @__quantum__qis__h__ctl(%Array* %__controlQubits__, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Y__body(%Qubit* %qb) { -entry: - call void @__quantum__qis__y__body(%Qubit* %qb) - ret void -} - -declare void @__quantum__qis__y__body(%Qubit*) - -define void @Microsoft__Quantum__Intrinsic__Y__adj(%Qubit* %qb) { -entry: - call void @__quantum__qis__y__body(%Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Y__ctl(%Array* %__controlQubits__, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 1) - call void @__quantum__qis__y__ctl(%Array* %__controlQubits__, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 -1) - ret void -} - -declare void @__quantum__qis__y__ctl(%Array*, %Qubit*) - -define void @Microsoft__Quantum__Intrinsic__Y__ctladj(%Array* %__controlQubits__, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 1) - call void @__quantum__qis__y__ctl(%Array* %__controlQubits__, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__R__body(i2 %pauli, double %theta, %Qubit* %qubit) { -entry: - call void @__quantum__qis__r__body(i2 %pauli, double %theta, %Qubit* %qubit) - ret void -} - -declare void @__quantum__qis__r__body(i2, double, %Qubit*) - -define void @Microsoft__Quantum__Intrinsic__R__adj(i2 %pauli, double %theta, %Qubit* %qubit) { -entry: - call void @__quantum__qis__r__adj(i2 %pauli, double %theta, %Qubit* %qubit) - ret void -} - -declare void @__quantum__qis__r__adj(i2, double, %Qubit*) - -define void @Microsoft__Quantum__Intrinsic__R__ctl(%Array* %__controlQubits__, { i2, double, %Qubit* }* %0) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 1) - %1 = getelementptr { i2, double, %Qubit* }, { i2, double, %Qubit* }* %0, i64 0, i32 0 - %pauli = load i2, i2* %1 - %2 = getelementptr { i2, double, %Qubit* }, { i2, double, %Qubit* }* %0, i64 0, i32 1 - %theta = load double, double* %2 - %3 = getelementptr { i2, double, %Qubit* }, { i2, double, %Qubit* }* %0, i64 0, i32 2 - %qubit = load %Qubit*, %Qubit** %3 - %4 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ i2, double, %Qubit* }* getelementptr ({ i2, double, %Qubit* }, { i2, double, %Qubit* }* null, i32 1) to i64)) - %5 = bitcast %Tuple* %4 to { i2, double, %Qubit* }* - %6 = getelementptr { i2, double, %Qubit* }, { i2, double, %Qubit* }* %5, i64 0, i32 0 - %7 = getelementptr { i2, double, %Qubit* }, { i2, double, %Qubit* }* %5, i64 0, i32 1 - %8 = getelementptr { i2, double, %Qubit* }, { i2, double, %Qubit* }* %5, i64 0, i32 2 - store i2 %pauli, i2* %6 - store double %theta, double* %7 - store %Qubit* %qubit, %Qubit** %8 - call void @__quantum__qis__r__ctl(%Array* %__controlQubits__, { i2, double, %Qubit* }* %5) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 -1) - call void @__quantum__rt__tuple_update_reference_count(%Tuple* %4, i64 -1) - ret void -} - -declare void @__quantum__qis__r__ctl(%Array*, { i2, double, %Qubit* }*) - -declare %Tuple* @__quantum__rt__tuple_create(i64) - -declare void @__quantum__rt__tuple_update_reference_count(%Tuple*, i64) - -define void @Microsoft__Quantum__Intrinsic__R__ctladj(%Array* %__controlQubits__, { i2, double, %Qubit* }* %0) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 1) - %1 = getelementptr { i2, double, %Qubit* }, { i2, double, %Qubit* }* %0, i64 0, i32 0 - %pauli = load i2, i2* %1 - %2 = getelementptr { i2, double, %Qubit* }, { i2, double, %Qubit* }* %0, i64 0, i32 1 - %theta = load double, double* %2 - %3 = getelementptr { i2, double, %Qubit* }, { i2, double, %Qubit* }* %0, i64 0, i32 2 - %qubit = load %Qubit*, %Qubit** %3 - %4 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ i2, double, %Qubit* }* getelementptr ({ i2, double, %Qubit* }, { i2, double, %Qubit* }* null, i32 1) to i64)) - %5 = bitcast %Tuple* %4 to { i2, double, %Qubit* }* - %6 = getelementptr { i2, double, %Qubit* }, { i2, double, %Qubit* }* %5, i64 0, i32 0 - %7 = getelementptr { i2, double, %Qubit* }, { i2, double, %Qubit* }* %5, i64 0, i32 1 - %8 = getelementptr { i2, double, %Qubit* }, { i2, double, %Qubit* }* %5, i64 0, i32 2 - store i2 %pauli, i2* %6 - store double %theta, double* %7 - store %Qubit* %qubit, %Qubit** %8 - call void @__quantum__qis__r__ctladj(%Array* %__controlQubits__, { i2, double, %Qubit* }* %5) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 -1) - call void @__quantum__rt__tuple_update_reference_count(%Tuple* %4, i64 -1) - ret void -} - -declare void @__quantum__qis__r__ctladj(%Array*, { i2, double, %Qubit* }*) - -define void @Microsoft__Quantum__Intrinsic__Exp__body(%Array* %paulis, double %theta, %Array* %qubits) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %paulis, i64 1) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 1) - call void @__quantum__qis__exp__body(%Array* %paulis, double %theta, %Array* %qubits) - call void @__quantum__rt__array_update_alias_count(%Array* %paulis, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 -1) - ret void -} - -declare void @__quantum__qis__exp__body(%Array*, double, %Array*) - -define void @Microsoft__Quantum__Intrinsic__Exp__adj(%Array* %paulis, double %theta, %Array* %qubits) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %paulis, i64 1) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 1) - call void @__quantum__qis__exp__adj(%Array* %paulis, double %theta, %Array* %qubits) - call void @__quantum__rt__array_update_alias_count(%Array* %paulis, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 -1) - ret void -} - -declare void @__quantum__qis__exp__adj(%Array*, double, %Array*) - -define void @Microsoft__Quantum__Intrinsic__Exp__ctl(%Array* %__controlQubits__, { %Array*, double, %Array* }* %0) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 1) - %1 = getelementptr { %Array*, double, %Array* }, { %Array*, double, %Array* }* %0, i64 0, i32 0 - %paulis = load %Array*, %Array** %1 - call void @__quantum__rt__array_update_alias_count(%Array* %paulis, i64 1) - %2 = getelementptr { %Array*, double, %Array* }, { %Array*, double, %Array* }* %0, i64 0, i32 1 - %theta = load double, double* %2 - %3 = getelementptr { %Array*, double, %Array* }, { %Array*, double, %Array* }* %0, i64 0, i32 2 - %qubits = load %Array*, %Array** %3 - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 1) - %4 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ %Array*, double, %Array* }* getelementptr ({ %Array*, double, %Array* }, { %Array*, double, %Array* }* null, i32 1) to i64)) - %5 = bitcast %Tuple* %4 to { %Array*, double, %Array* }* - %6 = getelementptr { %Array*, double, %Array* }, { %Array*, double, %Array* }* %5, i64 0, i32 0 - %7 = getelementptr { %Array*, double, %Array* }, { %Array*, double, %Array* }* %5, i64 0, i32 1 - %8 = getelementptr { %Array*, double, %Array* }, { %Array*, double, %Array* }* %5, i64 0, i32 2 - store %Array* %paulis, %Array** %6 - store double %theta, double* %7 - store %Array* %qubits, %Array** %8 - call void @__quantum__qis__exp__ctl(%Array* %__controlQubits__, { %Array*, double, %Array* }* %5) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %paulis, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 -1) - call void @__quantum__rt__tuple_update_reference_count(%Tuple* %4, i64 -1) - ret void -} - -declare void @__quantum__qis__exp__ctl(%Array*, { %Array*, double, %Array* }*) - -define void @Microsoft__Quantum__Intrinsic__Exp__ctladj(%Array* %__controlQubits__, { %Array*, double, %Array* }* %0) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 1) - %1 = getelementptr { %Array*, double, %Array* }, { %Array*, double, %Array* }* %0, i64 0, i32 0 - %paulis = load %Array*, %Array** %1 - call void @__quantum__rt__array_update_alias_count(%Array* %paulis, i64 1) - %2 = getelementptr { %Array*, double, %Array* }, { %Array*, double, %Array* }* %0, i64 0, i32 1 - %theta = load double, double* %2 - %3 = getelementptr { %Array*, double, %Array* }, { %Array*, double, %Array* }* %0, i64 0, i32 2 - %qubits = load %Array*, %Array** %3 - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 1) - %4 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ %Array*, double, %Array* }* getelementptr ({ %Array*, double, %Array* }, { %Array*, double, %Array* }* null, i32 1) to i64)) - %5 = bitcast %Tuple* %4 to { %Array*, double, %Array* }* - %6 = getelementptr { %Array*, double, %Array* }, { %Array*, double, %Array* }* %5, i64 0, i32 0 - %7 = getelementptr { %Array*, double, %Array* }, { %Array*, double, %Array* }* %5, i64 0, i32 1 - %8 = getelementptr { %Array*, double, %Array* }, { %Array*, double, %Array* }* %5, i64 0, i32 2 - store %Array* %paulis, %Array** %6 - store double %theta, double* %7 - store %Array* %qubits, %Array** %8 - call void @__quantum__qis__exp__ctladj(%Array* %__controlQubits__, { %Array*, double, %Array* }* %5) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %paulis, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 -1) - call void @__quantum__rt__tuple_update_reference_count(%Tuple* %4, i64 -1) - ret void -} - -declare void @__quantum__qis__exp__ctladj(%Array*, { %Array*, double, %Array* }*) - -define void @Microsoft__Quantum__Intrinsic__Z__body(%Qubit* %qb) { -entry: - call void @__quantum__qis__z__body(%Qubit* %qb) - ret void -} - -declare void @__quantum__qis__z__body(%Qubit*) - -define void @Microsoft__Quantum__Intrinsic__Z__adj(%Qubit* %qb) { -entry: - call void @__quantum__qis__z__body(%Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Z__ctl(%Array* %__controlQubits__, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 1) - call void @__quantum__qis__z__ctl(%Array* %__controlQubits__, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 -1) - ret void -} - -declare void @__quantum__qis__z__ctl(%Array*, %Qubit*) - -define void @Microsoft__Quantum__Intrinsic__Z__ctladj(%Array* %__controlQubits__, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 1) - call void @__quantum__qis__z__ctl(%Array* %__controlQubits__, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 -1) - ret void -} - -define i64 @Microsoft__Quantum__Testing__QIR__InvokeAllVariants__body(%Callable* %op) { -entry: - call void @__quantum__rt__callable_memory_management(i32 1, %Callable* %op, i64 1) - call void @__quantum__rt__callable_update_alias_count(%Callable* %op, i64 1) - %res = alloca i64 - store i64 0, i64* %res - %target = call %Qubit* @__quantum__rt__qubit_allocate() - %ctls = call %Array* @__quantum__rt__qubit_allocate_array(i64 2) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - %0 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64)) - %1 = bitcast %Tuple* %0 to { %Qubit* }* - %2 = getelementptr { %Qubit* }, { %Qubit* }* %1, i64 0, i32 0 - store %Qubit* %target, %Qubit** %2 - call void @__quantum__rt__callable_invoke(%Callable* %op, %Tuple* %0, %Tuple* null) - %3 = call %Callable* @__quantum__rt__callable_copy(%Callable* %op, i1 false) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %3, i64 1) - call void @__quantum__rt__callable_make_adjoint(%Callable* %3) - %4 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64)) - %5 = bitcast %Tuple* %4 to { %Qubit* }* - %6 = getelementptr { %Qubit* }, { %Qubit* }* %5, i64 0, i32 0 - store %Qubit* %target, %Qubit** %6 - call void @__quantum__rt__callable_invoke(%Callable* %3, %Tuple* %4, %Tuple* null) - %7 = call %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %target) - %8 = load %Result*, %Result** @ResultZero - %9 = call i1 @__quantum__rt__result_equal(%Result* %7, %Result* %8) - %10 = xor i1 %9, true - br i1 %10, label %then0__1, label %else__1 - -then0__1: ; preds = %entry - store i64 1, i64* %res - br label %continue__1 - -else__1: ; preds = %entry - %11 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 0) - %12 = bitcast i8* %11 to %Qubit** - %qb__inline__1 = load %Qubit*, %Qubit** %12 - call void @__quantum__qis__h__body(%Qubit* %qb__inline__1) - %13 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 1) - %14 = bitcast i8* %13 to %Qubit** - %qb__inline__2 = load %Qubit*, %Qubit** %14 - call void @__quantum__qis__h__body(%Qubit* %qb__inline__2) - %15 = call %Callable* @__quantum__rt__callable_copy(%Callable* %op, i1 false) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %15, i64 1) - call void @__quantum__rt__callable_make_controlled(%Callable* %15) - %16 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) - %17 = bitcast %Tuple* %16 to { %Array*, %Qubit* }* - %18 = getelementptr { %Array*, %Qubit* }, { %Array*, %Qubit* }* %17, i64 0, i32 0 - %19 = getelementptr { %Array*, %Qubit* }, { %Array*, %Qubit* }* %17, i64 0, i32 1 - store %Array* %ctls, %Array** %18 - store %Qubit* %target, %Qubit** %19 - call void @__quantum__rt__callable_invoke(%Callable* %15, %Tuple* %16, %Tuple* null) - %20 = call %Callable* @__quantum__rt__callable_copy(%Callable* %op, i1 false) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %20, i64 1) - call void @__quantum__rt__callable_make_controlled(%Callable* %20) - call void @__quantum__rt__callable_make_adjoint(%Callable* %20) - %21 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) - %22 = bitcast %Tuple* %21 to { %Array*, %Qubit* }* - %23 = getelementptr { %Array*, %Qubit* }, { %Array*, %Qubit* }* %22, i64 0, i32 0 - %24 = getelementptr { %Array*, %Qubit* }, { %Array*, %Qubit* }* %22, i64 0, i32 1 - store %Array* %ctls, %Array** %23 - store %Qubit* %target, %Qubit** %24 - call void @__quantum__rt__callable_invoke(%Callable* %20, %Tuple* %21, %Tuple* null) - %25 = call %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %target) - %26 = load %Result*, %Result** @ResultZero - %27 = call i1 @__quantum__rt__result_equal(%Result* %25, %Result* %26) - %28 = xor i1 %27, true - br i1 %28, label %then0__2, label %continue__2 - -then0__2: ; preds = %else__1 - store i64 2, i64* %res - br label %continue__2 - -continue__2: ; preds = %then0__2, %else__1 - %29 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 0) - %30 = bitcast i8* %29 to %Qubit** - %qb__inline__3 = load %Qubit*, %Qubit** %30 - call void @__quantum__qis__h__body(%Qubit* %qb__inline__3) - %31 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 1) - %32 = bitcast i8* %31 to %Qubit** - %qb__inline__4 = load %Qubit*, %Qubit** %32 - call void @__quantum__qis__h__body(%Qubit* %qb__inline__4) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %15, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %15, i64 -1) - call void @__quantum__rt__tuple_update_reference_count(%Tuple* %16, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %20, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %20, i64 -1) - call void @__quantum__rt__tuple_update_reference_count(%Tuple* %21, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %25, i64 -1) - br label %continue__1 - -continue__1: ; preds = %continue__2, %then0__1 - call void @__quantum__rt__qubit_release(%Qubit* %target) - call void @__quantum__rt__qubit_release_array(%Array* %ctls) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i64 -1) - call void @__quantum__rt__tuple_update_reference_count(%Tuple* %0, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %3, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %3, i64 -1) - call void @__quantum__rt__tuple_update_reference_count(%Tuple* %4, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %7, i64 -1) - %33 = load i64, i64* %res - call void @__quantum__rt__callable_memory_management(i32 1, %Callable* %op, i64 -1) - call void @__quantum__rt__callable_update_alias_count(%Callable* %op, i64 -1) - ret i64 %33 -} - -declare void @__quantum__rt__callable_memory_management(i32, %Callable*, i64) - -declare void @__quantum__rt__callable_update_alias_count(%Callable*, i64) - -declare %Qubit* @__quantum__rt__qubit_allocate() - -declare %Array* @__quantum__rt__qubit_allocate_array(i64) - -declare void @__quantum__rt__callable_invoke(%Callable*, %Tuple*, %Tuple*) - -declare %Callable* @__quantum__rt__callable_copy(%Callable*, i1) - -declare void @__quantum__rt__callable_make_adjoint(%Callable*) - -declare i1 @__quantum__rt__result_equal(%Result*, %Result*) - -declare void @__quantum__rt__callable_make_controlled(%Callable*) - -declare void @__quantum__rt__callable_update_reference_count(%Callable*, i64) - -declare void @__quantum__rt__result_update_reference_count(%Result*, i64) - -declare void @__quantum__rt__qubit_release(%Qubit*) - -declare void @__quantum__rt__qubit_release_array(%Array*) - -define i64 @Microsoft__Quantum__Testing__QIR__Test_Simulator_QIS__body() #0 { -entry: - %res = alloca i64 - store i64 0, i64* %res - %0 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__X, [2 x void (%Tuple*, i64)*]* null, %Tuple* null) - %1 = call i64 @Microsoft__Quantum__Testing__QIR__InvokeAllVariants__body(%Callable* %0) - store i64 %1, i64* %res - %2 = icmp ne i64 %1, 0 - br i1 %2, label %then0__1, label %continue__1 - -then0__1: ; preds = %entry - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %0, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %0, i64 -1) - ret i64 %1 - -continue__1: ; preds = %entry - %3 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__Y, [2 x void (%Tuple*, i64)*]* null, %Tuple* null) - %4 = call i64 @Microsoft__Quantum__Testing__QIR__InvokeAllVariants__body(%Callable* %3) - store i64 %4, i64* %res - %5 = icmp ne i64 %4, 0 - br i1 %5, label %then0__2, label %continue__2 - -then0__2: ; preds = %continue__1 - %6 = add i64 10, %4 - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %0, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %0, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %3, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %3, i64 -1) - ret i64 %6 - -continue__2: ; preds = %continue__1 - %7 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__Z, [2 x void (%Tuple*, i64)*]* null, %Tuple* null) - %8 = call i64 @Microsoft__Quantum__Testing__QIR__InvokeAllVariants__body(%Callable* %7) - store i64 %8, i64* %res - %9 = icmp ne i64 %8, 0 - br i1 %9, label %then0__3, label %continue__3 - -then0__3: ; preds = %continue__2 - %10 = add i64 20, %8 - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %0, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %0, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %3, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %3, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %7, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %7, i64 -1) - ret i64 %10 - -continue__3: ; preds = %continue__2 - %11 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__H, [2 x void (%Tuple*, i64)*]* null, %Tuple* null) - %12 = call i64 @Microsoft__Quantum__Testing__QIR__InvokeAllVariants__body(%Callable* %11) - store i64 %12, i64* %res - %13 = icmp ne i64 %12, 0 - br i1 %13, label %then0__4, label %continue__4 - -then0__4: ; preds = %continue__3 - %14 = add i64 30, %12 - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %0, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %0, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %3, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %3, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %7, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %7, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %11, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %11, i64 -1) - ret i64 %14 - -continue__4: ; preds = %continue__3 - %15 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__S, [2 x void (%Tuple*, i64)*]* null, %Tuple* null) - %16 = call i64 @Microsoft__Quantum__Testing__QIR__InvokeAllVariants__body(%Callable* %15) - store i64 %16, i64* %res - %17 = icmp ne i64 %16, 0 - br i1 %17, label %then0__5, label %continue__5 - -then0__5: ; preds = %continue__4 - %18 = add i64 40, %16 - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %0, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %0, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %3, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %3, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %7, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %7, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %11, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %11, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %15, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %15, i64 -1) - ret i64 %18 - -continue__5: ; preds = %continue__4 - %19 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__T, [2 x void (%Tuple*, i64)*]* null, %Tuple* null) - %20 = call i64 @Microsoft__Quantum__Testing__QIR__InvokeAllVariants__body(%Callable* %19) - store i64 %20, i64* %res - %21 = icmp ne i64 %20, 0 - br i1 %21, label %then0__6, label %continue__6 - -then0__6: ; preds = %continue__5 - %22 = add i64 50, %20 - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %0, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %0, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %3, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %3, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %7, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %7, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %11, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %11, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %15, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %15, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %19, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %19, i64 -1) - ret i64 %22 - -continue__6: ; preds = %continue__5 - %23 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ %Callable*, i2, double }* getelementptr ({ %Callable*, i2, double }, { %Callable*, i2, double }* null, i32 1) to i64)) - %24 = bitcast %Tuple* %23 to { %Callable*, i2, double }* - %25 = getelementptr { %Callable*, i2, double }, { %Callable*, i2, double }* %24, i64 0, i32 0 - %26 = getelementptr { %Callable*, i2, double }, { %Callable*, i2, double }* %24, i64 0, i32 1 - %27 = getelementptr { %Callable*, i2, double }, { %Callable*, i2, double }* %24, i64 0, i32 2 - %28 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__R, [2 x void (%Tuple*, i64)*]* null, %Tuple* null) - %29 = load i2, i2* @PauliX - store %Callable* %28, %Callable** %25 - store i2 %29, i2* %26 - store double 4.200000e-01, double* %27 - %30 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @PartialApplication__1, [2 x void (%Tuple*, i64)*]* @MemoryManagement__1, %Tuple* %23) - %31 = call i64 @Microsoft__Quantum__Testing__QIR__InvokeAllVariants__body(%Callable* %30) - store i64 %31, i64* %res - %32 = icmp ne i64 %31, 0 - br i1 %32, label %then0__7, label %continue__7 - -then0__7: ; preds = %continue__6 - %33 = add i64 60, %31 - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %0, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %0, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %3, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %3, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %7, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %7, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %11, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %11, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %15, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %15, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %19, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %19, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %30, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %30, i64 -1) - ret i64 %33 - -continue__7: ; preds = %continue__6 - %targets = call %Array* @__quantum__rt__qubit_allocate_array(i64 2) - call void @__quantum__rt__array_update_alias_count(%Array* %targets, i64 1) - %ctls = call %Array* @__quantum__rt__qubit_allocate_array(i64 2) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - %paulis__inline__1 = call %Array* @__quantum__rt__array_create_1d(i32 1, i64 2) - %34 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis__inline__1, i64 0) - %35 = bitcast i8* %34 to i2* - %36 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis__inline__1, i64 1) - %37 = bitcast i8* %36 to i2* - %38 = load i2, i2* @PauliX - %39 = load i2, i2* @PauliY - store i2 %38, i2* %35 - store i2 %39, i2* %37 - call void @__quantum__rt__array_update_alias_count(%Array* %paulis__inline__1, i64 1) - call void @__quantum__rt__array_update_alias_count(%Array* %targets, i64 1) - call void @__quantum__qis__exp__body(%Array* %paulis__inline__1, double 4.200000e-01, %Array* %targets) - call void @__quantum__rt__array_update_alias_count(%Array* %paulis__inline__1, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %targets, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %paulis__inline__1, i64 -1) - %paulis__inline__2 = call %Array* @__quantum__rt__array_create_1d(i32 1, i64 2) - %40 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis__inline__2, i64 0) - %41 = bitcast i8* %40 to i2* - %42 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis__inline__2, i64 1) - %43 = bitcast i8* %42 to i2* - %44 = load i2, i2* @PauliX - %45 = load i2, i2* @PauliY - store i2 %44, i2* %41 - store i2 %45, i2* %43 - call void @__quantum__rt__array_update_alias_count(%Array* %paulis__inline__2, i64 1) - call void @__quantum__rt__array_update_alias_count(%Array* %targets, i64 1) - call void @__quantum__qis__exp__adj(%Array* %paulis__inline__2, double 4.200000e-01, %Array* %targets) - call void @__quantum__rt__array_update_alias_count(%Array* %paulis__inline__2, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %targets, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %paulis__inline__2, i64 -1) - %46 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %targets, i64 0) - %47 = bitcast i8* %46 to %Qubit** - %48 = load %Qubit*, %Qubit** %47 - %49 = call %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %48) - %50 = load %Result*, %Result** @ResultZero - %51 = call i1 @__quantum__rt__result_equal(%Result* %49, %Result* %50) - %52 = xor i1 %51, true - %53 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %targets, i64 1) - %54 = bitcast i8* %53 to %Qubit** - %55 = load %Qubit*, %Qubit** %54 - %56 = call %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %55) - %57 = load %Result*, %Result** @ResultZero - %58 = call i1 @__quantum__rt__result_equal(%Result* %56, %Result* %57) - %59 = xor i1 %58, true - %60 = or i1 %52, %59 - br i1 %60, label %then0__8, label %else__1 - -then0__8: ; preds = %continue__7 - store i64 1, i64* %res - br label %continue__8 - -else__1: ; preds = %continue__7 - %61 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 0) - %62 = bitcast i8* %61 to %Qubit** - %qb__inline__3 = load %Qubit*, %Qubit** %62 - call void @__quantum__qis__h__body(%Qubit* %qb__inline__3) - %63 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 1) - %64 = bitcast i8* %63 to %Qubit** - %qb__inline__4 = load %Qubit*, %Qubit** %64 - call void @__quantum__qis__h__body(%Qubit* %qb__inline__4) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - %paulis__inline__5 = call %Array* @__quantum__rt__array_create_1d(i32 1, i64 2) - %65 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis__inline__5, i64 0) - %66 = bitcast i8* %65 to i2* - %67 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis__inline__5, i64 1) - %68 = bitcast i8* %67 to i2* - %69 = load i2, i2* @PauliX - %70 = load i2, i2* @PauliY - store i2 %69, i2* %66 - store i2 %70, i2* %68 - call void @__quantum__rt__array_update_alias_count(%Array* %paulis__inline__5, i64 1) - call void @__quantum__rt__array_update_alias_count(%Array* %targets, i64 1) - %71 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ %Array*, double, %Array* }* getelementptr ({ %Array*, double, %Array* }, { %Array*, double, %Array* }* null, i32 1) to i64)) - %72 = bitcast %Tuple* %71 to { %Array*, double, %Array* }* - %73 = getelementptr { %Array*, double, %Array* }, { %Array*, double, %Array* }* %72, i64 0, i32 0 - %74 = getelementptr { %Array*, double, %Array* }, { %Array*, double, %Array* }* %72, i64 0, i32 1 - %75 = getelementptr { %Array*, double, %Array* }, { %Array*, double, %Array* }* %72, i64 0, i32 2 - store %Array* %paulis__inline__5, %Array** %73 - store double 4.200000e-01, double* %74 - store %Array* %targets, %Array** %75 - call void @__quantum__qis__exp__ctl(%Array* %ctls, { %Array*, double, %Array* }* %72) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %paulis__inline__5, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %targets, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %paulis__inline__5, i64 -1) - call void @__quantum__rt__tuple_update_reference_count(%Tuple* %71, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - %paulis__inline__6 = call %Array* @__quantum__rt__array_create_1d(i32 1, i64 2) - %76 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis__inline__6, i64 0) - %77 = bitcast i8* %76 to i2* - %78 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis__inline__6, i64 1) - %79 = bitcast i8* %78 to i2* - %80 = load i2, i2* @PauliX - %81 = load i2, i2* @PauliY - store i2 %80, i2* %77 - store i2 %81, i2* %79 - call void @__quantum__rt__array_update_alias_count(%Array* %paulis__inline__6, i64 1) - call void @__quantum__rt__array_update_alias_count(%Array* %targets, i64 1) - %82 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ %Array*, double, %Array* }* getelementptr ({ %Array*, double, %Array* }, { %Array*, double, %Array* }* null, i32 1) to i64)) - %83 = bitcast %Tuple* %82 to { %Array*, double, %Array* }* - %84 = getelementptr { %Array*, double, %Array* }, { %Array*, double, %Array* }* %83, i64 0, i32 0 - %85 = getelementptr { %Array*, double, %Array* }, { %Array*, double, %Array* }* %83, i64 0, i32 1 - %86 = getelementptr { %Array*, double, %Array* }, { %Array*, double, %Array* }* %83, i64 0, i32 2 - store %Array* %paulis__inline__6, %Array** %84 - store double 4.200000e-01, double* %85 - store %Array* %targets, %Array** %86 - call void @__quantum__qis__exp__ctladj(%Array* %ctls, { %Array*, double, %Array* }* %83) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %paulis__inline__6, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %targets, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %paulis__inline__6, i64 -1) - call void @__quantum__rt__tuple_update_reference_count(%Tuple* %82, i64 -1) - %87 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 0) - %88 = bitcast i8* %87 to %Qubit** - %qb__inline__7 = load %Qubit*, %Qubit** %88 - call void @__quantum__qis__h__body(%Qubit* %qb__inline__7) - %89 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 1) - %90 = bitcast i8* %89 to %Qubit** - %qb__inline__8 = load %Qubit*, %Qubit** %90 - call void @__quantum__qis__h__body(%Qubit* %qb__inline__8) - %91 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %targets, i64 0) - %92 = bitcast i8* %91 to %Qubit** - %93 = load %Qubit*, %Qubit** %92 - %94 = call %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %93) - %95 = load %Result*, %Result** @ResultZero - %96 = call i1 @__quantum__rt__result_equal(%Result* %94, %Result* %95) - %97 = xor i1 %96, true - %98 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %targets, i64 1) - %99 = bitcast i8* %98 to %Qubit** - %100 = load %Qubit*, %Qubit** %99 - %101 = call %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %100) - %102 = load %Result*, %Result** @ResultZero - %103 = call i1 @__quantum__rt__result_equal(%Result* %101, %Result* %102) - %104 = xor i1 %103, true - %105 = or i1 %97, %104 - br i1 %105, label %then0__9, label %continue__9 - -then0__9: ; preds = %else__1 - store i64 72, i64* %res - br label %continue__9 - -continue__9: ; preds = %then0__9, %else__1 - call void @__quantum__rt__result_update_reference_count(%Result* %94, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %101, i64 -1) - br label %continue__8 - -continue__8: ; preds = %continue__9, %then0__8 - call void @__quantum__rt__qubit_release_array(%Array* %targets) - call void @__quantum__rt__qubit_release_array(%Array* %ctls) - call void @__quantum__rt__array_update_alias_count(%Array* %targets, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %targets, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %49, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %56, i64 -1) - %106 = load i64, i64* %res - %107 = icmp ne i64 %106, 0 - br i1 %107, label %then0__10, label %continue__10 - -then0__10: ; preds = %continue__8 - %108 = add i64 70, %106 - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %0, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %0, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %3, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %3, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %7, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %7, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %11, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %11, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %15, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %15, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %19, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %19, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %30, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %30, i64 -1) - ret i64 %108 - -continue__10: ; preds = %continue__8 - %qs = call %Array* @__quantum__rt__qubit_allocate_array(i64 3) - call void @__quantum__rt__array_update_alias_count(%Array* %qs, i64 1) - %109 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 0) - %110 = bitcast i8* %109 to %Qubit** - %qb__inline__9 = load %Qubit*, %Qubit** %110 - call void @__quantum__qis__h__body(%Qubit* %qb__inline__9) - %111 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 2) - %112 = bitcast i8* %111 to %Qubit** - %qb__inline__10 = load %Qubit*, %Qubit** %112 - call void @__quantum__qis__h__body(%Qubit* %qb__inline__10) - %bases__inline__11 = call %Array* @__quantum__rt__array_create_1d(i32 1, i64 3) - %113 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %bases__inline__11, i64 0) - %114 = bitcast i8* %113 to i2* - %115 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %bases__inline__11, i64 1) - %116 = bitcast i8* %115 to i2* - %117 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %bases__inline__11, i64 2) - %118 = bitcast i8* %117 to i2* - %119 = load i2, i2* @PauliX - %120 = load i2, i2* @PauliZ - %121 = load i2, i2* @PauliX - store i2 %119, i2* %114 - store i2 %120, i2* %116 - store i2 %121, i2* %118 - call void @__quantum__rt__array_update_alias_count(%Array* %bases__inline__11, i64 1) - call void @__quantum__rt__array_update_alias_count(%Array* %qs, i64 1) - %122 = call %Result* @__quantum__qis__measure__body(%Array* %bases__inline__11, %Array* %qs) - call void @__quantum__rt__array_update_alias_count(%Array* %bases__inline__11, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %qs, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %bases__inline__11, i64 -1) - %123 = load %Result*, %Result** @ResultZero - %124 = call i1 @__quantum__rt__result_equal(%Result* %122, %Result* %123) - %125 = xor i1 %124, true - br i1 %125, label %then0__11, label %continue__11 - -then0__11: ; preds = %continue__10 - store i64 80, i64* %res - br label %continue__11 - -continue__11: ; preds = %then0__11, %continue__10 - %126 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 0) - %127 = bitcast i8* %126 to %Qubit** - %qb__inline__12 = load %Qubit*, %Qubit** %127 - call void @__quantum__qis__h__body(%Qubit* %qb__inline__12) - %128 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 2) - %129 = bitcast i8* %128 to %Qubit** - %qb__inline__13 = load %Qubit*, %Qubit** %129 - call void @__quantum__qis__h__body(%Qubit* %qb__inline__13) - call void @__quantum__rt__qubit_release_array(%Array* %qs) - call void @__quantum__rt__array_update_alias_count(%Array* %qs, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %qs, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %122, i64 -1) - %130 = load i64, i64* %res - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %0, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %0, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %3, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %3, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %7, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %7, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %11, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %11, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %15, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %15, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %19, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %19, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %30, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %30, i64 -1) - ret i64 %130 -} - -define void @Microsoft__Quantum__Intrinsic__X__body__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Qubit* }* - %1 = getelementptr { %Qubit* }, { %Qubit* }* %0, i64 0, i32 0 - %2 = load %Qubit*, %Qubit** %1 - call void @Microsoft__Quantum__Intrinsic__X__body(%Qubit* %2) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__X__adj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Qubit* }* - %1 = getelementptr { %Qubit* }, { %Qubit* }* %0, i64 0, i32 0 - %2 = load %Qubit*, %Qubit** %1 - call void @Microsoft__Quantum__Intrinsic__X__adj(%Qubit* %2) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__X__ctl__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Array*, %Qubit* }* - %1 = getelementptr { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i64 0, i32 0 - %2 = getelementptr { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i64 0, i32 1 - %3 = load %Array*, %Array** %1 - %4 = load %Qubit*, %Qubit** %2 - call void @Microsoft__Quantum__Intrinsic__X__ctl(%Array* %3, %Qubit* %4) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__X__ctladj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Array*, %Qubit* }* - %1 = getelementptr { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i64 0, i32 0 - %2 = getelementptr { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i64 0, i32 1 - %3 = load %Array*, %Array** %1 - %4 = load %Qubit*, %Qubit** %2 - call void @Microsoft__Quantum__Intrinsic__X__ctladj(%Array* %3, %Qubit* %4) - ret void -} - -declare %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]*, [2 x void (%Tuple*, i64)*]*, %Tuple*) - -define void @Microsoft__Quantum__Intrinsic__Y__body__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Qubit* }* - %1 = getelementptr { %Qubit* }, { %Qubit* }* %0, i64 0, i32 0 - %2 = load %Qubit*, %Qubit** %1 - call void @Microsoft__Quantum__Intrinsic__Y__body(%Qubit* %2) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Y__adj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Qubit* }* - %1 = getelementptr { %Qubit* }, { %Qubit* }* %0, i64 0, i32 0 - %2 = load %Qubit*, %Qubit** %1 - call void @Microsoft__Quantum__Intrinsic__Y__adj(%Qubit* %2) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Y__ctl__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Array*, %Qubit* }* - %1 = getelementptr { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i64 0, i32 0 - %2 = getelementptr { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i64 0, i32 1 - %3 = load %Array*, %Array** %1 - %4 = load %Qubit*, %Qubit** %2 - call void @Microsoft__Quantum__Intrinsic__Y__ctl(%Array* %3, %Qubit* %4) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Y__ctladj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Array*, %Qubit* }* - %1 = getelementptr { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i64 0, i32 0 - %2 = getelementptr { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i64 0, i32 1 - %3 = load %Array*, %Array** %1 - %4 = load %Qubit*, %Qubit** %2 - call void @Microsoft__Quantum__Intrinsic__Y__ctladj(%Array* %3, %Qubit* %4) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Z__body__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Qubit* }* - %1 = getelementptr { %Qubit* }, { %Qubit* }* %0, i64 0, i32 0 - %2 = load %Qubit*, %Qubit** %1 - call void @Microsoft__Quantum__Intrinsic__Z__body(%Qubit* %2) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Z__adj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Qubit* }* - %1 = getelementptr { %Qubit* }, { %Qubit* }* %0, i64 0, i32 0 - %2 = load %Qubit*, %Qubit** %1 - call void @Microsoft__Quantum__Intrinsic__Z__adj(%Qubit* %2) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Z__ctl__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Array*, %Qubit* }* - %1 = getelementptr { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i64 0, i32 0 - %2 = getelementptr { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i64 0, i32 1 - %3 = load %Array*, %Array** %1 - %4 = load %Qubit*, %Qubit** %2 - call void @Microsoft__Quantum__Intrinsic__Z__ctl(%Array* %3, %Qubit* %4) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Z__ctladj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Array*, %Qubit* }* - %1 = getelementptr { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i64 0, i32 0 - %2 = getelementptr { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i64 0, i32 1 - %3 = load %Array*, %Array** %1 - %4 = load %Qubit*, %Qubit** %2 - call void @Microsoft__Quantum__Intrinsic__Z__ctladj(%Array* %3, %Qubit* %4) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__H__body__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Qubit* }* - %1 = getelementptr { %Qubit* }, { %Qubit* }* %0, i64 0, i32 0 - %2 = load %Qubit*, %Qubit** %1 - call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %2) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__H__adj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Qubit* }* - %1 = getelementptr { %Qubit* }, { %Qubit* }* %0, i64 0, i32 0 - %2 = load %Qubit*, %Qubit** %1 - call void @Microsoft__Quantum__Intrinsic__H__adj(%Qubit* %2) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__H__ctl__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Array*, %Qubit* }* - %1 = getelementptr { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i64 0, i32 0 - %2 = getelementptr { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i64 0, i32 1 - %3 = load %Array*, %Array** %1 - %4 = load %Qubit*, %Qubit** %2 - call void @Microsoft__Quantum__Intrinsic__H__ctl(%Array* %3, %Qubit* %4) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__H__ctladj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Array*, %Qubit* }* - %1 = getelementptr { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i64 0, i32 0 - %2 = getelementptr { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i64 0, i32 1 - %3 = load %Array*, %Array** %1 - %4 = load %Qubit*, %Qubit** %2 - call void @Microsoft__Quantum__Intrinsic__H__ctladj(%Array* %3, %Qubit* %4) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__S__body__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Qubit* }* - %1 = getelementptr { %Qubit* }, { %Qubit* }* %0, i64 0, i32 0 - %2 = load %Qubit*, %Qubit** %1 - call void @Microsoft__Quantum__Intrinsic__S__body(%Qubit* %2) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__S__adj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Qubit* }* - %1 = getelementptr { %Qubit* }, { %Qubit* }* %0, i64 0, i32 0 - %2 = load %Qubit*, %Qubit** %1 - call void @Microsoft__Quantum__Intrinsic__S__adj(%Qubit* %2) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__S__ctl__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Array*, %Qubit* }* - %1 = getelementptr { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i64 0, i32 0 - %2 = getelementptr { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i64 0, i32 1 - %3 = load %Array*, %Array** %1 - %4 = load %Qubit*, %Qubit** %2 - call void @Microsoft__Quantum__Intrinsic__S__ctl(%Array* %3, %Qubit* %4) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__S__ctladj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Array*, %Qubit* }* - %1 = getelementptr { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i64 0, i32 0 - %2 = getelementptr { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i64 0, i32 1 - %3 = load %Array*, %Array** %1 - %4 = load %Qubit*, %Qubit** %2 - call void @Microsoft__Quantum__Intrinsic__S__ctladj(%Array* %3, %Qubit* %4) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__T__body__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Qubit* }* - %1 = getelementptr { %Qubit* }, { %Qubit* }* %0, i64 0, i32 0 - %2 = load %Qubit*, %Qubit** %1 - call void @Microsoft__Quantum__Intrinsic__T__body(%Qubit* %2) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__T__adj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Qubit* }* - %1 = getelementptr { %Qubit* }, { %Qubit* }* %0, i64 0, i32 0 - %2 = load %Qubit*, %Qubit** %1 - call void @Microsoft__Quantum__Intrinsic__T__adj(%Qubit* %2) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__T__ctl__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Array*, %Qubit* }* - %1 = getelementptr { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i64 0, i32 0 - %2 = getelementptr { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i64 0, i32 1 - %3 = load %Array*, %Array** %1 - %4 = load %Qubit*, %Qubit** %2 - call void @Microsoft__Quantum__Intrinsic__T__ctl(%Array* %3, %Qubit* %4) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__T__ctladj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Array*, %Qubit* }* - %1 = getelementptr { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i64 0, i32 0 - %2 = getelementptr { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i64 0, i32 1 - %3 = load %Array*, %Array** %1 - %4 = load %Qubit*, %Qubit** %2 - call void @Microsoft__Quantum__Intrinsic__T__ctladj(%Array* %3, %Qubit* %4) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__R__body__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { i2, double, %Qubit* }* - %1 = getelementptr { i2, double, %Qubit* }, { i2, double, %Qubit* }* %0, i64 0, i32 0 - %2 = getelementptr { i2, double, %Qubit* }, { i2, double, %Qubit* }* %0, i64 0, i32 1 - %3 = getelementptr { i2, double, %Qubit* }, { i2, double, %Qubit* }* %0, i64 0, i32 2 - %4 = load i2, i2* %1 - %5 = load double, double* %2 - %6 = load %Qubit*, %Qubit** %3 - call void @Microsoft__Quantum__Intrinsic__R__body(i2 %4, double %5, %Qubit* %6) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__R__adj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { i2, double, %Qubit* }* - %1 = getelementptr { i2, double, %Qubit* }, { i2, double, %Qubit* }* %0, i64 0, i32 0 - %2 = getelementptr { i2, double, %Qubit* }, { i2, double, %Qubit* }* %0, i64 0, i32 1 - %3 = getelementptr { i2, double, %Qubit* }, { i2, double, %Qubit* }* %0, i64 0, i32 2 - %4 = load i2, i2* %1 - %5 = load double, double* %2 - %6 = load %Qubit*, %Qubit** %3 - call void @Microsoft__Quantum__Intrinsic__R__adj(i2 %4, double %5, %Qubit* %6) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__R__ctl__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Array*, { i2, double, %Qubit* }* }* - %1 = getelementptr { %Array*, { i2, double, %Qubit* }* }, { %Array*, { i2, double, %Qubit* }* }* %0, i64 0, i32 0 - %2 = getelementptr { %Array*, { i2, double, %Qubit* }* }, { %Array*, { i2, double, %Qubit* }* }* %0, i64 0, i32 1 - %3 = load %Array*, %Array** %1 - %4 = load { i2, double, %Qubit* }*, { i2, double, %Qubit* }** %2 - call void @Microsoft__Quantum__Intrinsic__R__ctl(%Array* %3, { i2, double, %Qubit* }* %4) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__R__ctladj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Array*, { i2, double, %Qubit* }* }* - %1 = getelementptr { %Array*, { i2, double, %Qubit* }* }, { %Array*, { i2, double, %Qubit* }* }* %0, i64 0, i32 0 - %2 = getelementptr { %Array*, { i2, double, %Qubit* }* }, { %Array*, { i2, double, %Qubit* }* }* %0, i64 0, i32 1 - %3 = load %Array*, %Array** %1 - %4 = load { i2, double, %Qubit* }*, { i2, double, %Qubit* }** %2 - call void @Microsoft__Quantum__Intrinsic__R__ctladj(%Array* %3, { i2, double, %Qubit* }* %4) - ret void -} - -define void @Lifted__PartialApplication__1__body__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %capture-tuple to { %Callable*, i2, double }* - %1 = getelementptr { %Callable*, i2, double }, { %Callable*, i2, double }* %0, i64 0, i32 1 - %2 = load i2, i2* %1 - %3 = getelementptr { %Callable*, i2, double }, { %Callable*, i2, double }* %0, i64 0, i32 2 - %4 = load double, double* %3 - %5 = bitcast %Tuple* %arg-tuple to { %Qubit* }* - %6 = getelementptr { %Qubit* }, { %Qubit* }* %5, i64 0, i32 0 - %7 = load %Qubit*, %Qubit** %6 - %8 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ i2, double, %Qubit* }* getelementptr ({ i2, double, %Qubit* }, { i2, double, %Qubit* }* null, i32 1) to i64)) - %9 = bitcast %Tuple* %8 to { i2, double, %Qubit* }* - %10 = getelementptr { i2, double, %Qubit* }, { i2, double, %Qubit* }* %9, i64 0, i32 0 - %11 = getelementptr { i2, double, %Qubit* }, { i2, double, %Qubit* }* %9, i64 0, i32 1 - %12 = getelementptr { i2, double, %Qubit* }, { i2, double, %Qubit* }* %9, i64 0, i32 2 - store i2 %2, i2* %10 - store double %4, double* %11 - store %Qubit* %7, %Qubit** %12 - %13 = getelementptr { %Callable*, i2, double }, { %Callable*, i2, double }* %0, i64 0, i32 0 - %14 = load %Callable*, %Callable** %13 - call void @__quantum__rt__callable_invoke(%Callable* %14, %Tuple* %8, %Tuple* %result-tuple) - call void @__quantum__rt__tuple_update_reference_count(%Tuple* %8, i64 -1) - ret void -} - -define void @Lifted__PartialApplication__1__adj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %capture-tuple to { %Callable*, i2, double }* - %1 = getelementptr { %Callable*, i2, double }, { %Callable*, i2, double }* %0, i64 0, i32 1 - %2 = load i2, i2* %1 - %3 = getelementptr { %Callable*, i2, double }, { %Callable*, i2, double }* %0, i64 0, i32 2 - %4 = load double, double* %3 - %5 = bitcast %Tuple* %arg-tuple to { %Qubit* }* - %6 = getelementptr { %Qubit* }, { %Qubit* }* %5, i64 0, i32 0 - %7 = load %Qubit*, %Qubit** %6 - %8 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ i2, double, %Qubit* }* getelementptr ({ i2, double, %Qubit* }, { i2, double, %Qubit* }* null, i32 1) to i64)) - %9 = bitcast %Tuple* %8 to { i2, double, %Qubit* }* - %10 = getelementptr { i2, double, %Qubit* }, { i2, double, %Qubit* }* %9, i64 0, i32 0 - %11 = getelementptr { i2, double, %Qubit* }, { i2, double, %Qubit* }* %9, i64 0, i32 1 - %12 = getelementptr { i2, double, %Qubit* }, { i2, double, %Qubit* }* %9, i64 0, i32 2 - store i2 %2, i2* %10 - store double %4, double* %11 - store %Qubit* %7, %Qubit** %12 - %13 = getelementptr { %Callable*, i2, double }, { %Callable*, i2, double }* %0, i64 0, i32 0 - %14 = load %Callable*, %Callable** %13 - %15 = call %Callable* @__quantum__rt__callable_copy(%Callable* %14, i1 false) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %15, i64 1) - call void @__quantum__rt__callable_make_adjoint(%Callable* %15) - call void @__quantum__rt__callable_invoke(%Callable* %15, %Tuple* %8, %Tuple* %result-tuple) - call void @__quantum__rt__tuple_update_reference_count(%Tuple* %8, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %15, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %15, i64 -1) - ret void -} - -define void @Lifted__PartialApplication__1__ctl__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Array*, %Qubit* }* - %1 = getelementptr { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i64 0, i32 0 - %2 = getelementptr { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i64 0, i32 1 - %3 = load %Array*, %Array** %1 - %4 = load %Qubit*, %Qubit** %2 - %5 = bitcast %Tuple* %capture-tuple to { %Callable*, i2, double }* - %6 = getelementptr { %Callable*, i2, double }, { %Callable*, i2, double }* %5, i64 0, i32 1 - %7 = load i2, i2* %6 - %8 = getelementptr { %Callable*, i2, double }, { %Callable*, i2, double }* %5, i64 0, i32 2 - %9 = load double, double* %8 - %10 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ i2, double, %Qubit* }* getelementptr ({ i2, double, %Qubit* }, { i2, double, %Qubit* }* null, i32 1) to i64)) - %11 = bitcast %Tuple* %10 to { i2, double, %Qubit* }* - %12 = getelementptr { i2, double, %Qubit* }, { i2, double, %Qubit* }* %11, i64 0, i32 0 - %13 = getelementptr { i2, double, %Qubit* }, { i2, double, %Qubit* }* %11, i64 0, i32 1 - %14 = getelementptr { i2, double, %Qubit* }, { i2, double, %Qubit* }* %11, i64 0, i32 2 - store i2 %7, i2* %12 - store double %9, double* %13 - store %Qubit* %4, %Qubit** %14 - %15 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) - %16 = bitcast %Tuple* %15 to { %Array*, { i2, double, %Qubit* }* }* - %17 = getelementptr { %Array*, { i2, double, %Qubit* }* }, { %Array*, { i2, double, %Qubit* }* }* %16, i64 0, i32 0 - %18 = getelementptr { %Array*, { i2, double, %Qubit* }* }, { %Array*, { i2, double, %Qubit* }* }* %16, i64 0, i32 1 - store %Array* %3, %Array** %17 - store { i2, double, %Qubit* }* %11, { i2, double, %Qubit* }** %18 - %19 = getelementptr { %Callable*, i2, double }, { %Callable*, i2, double }* %5, i64 0, i32 0 - %20 = load %Callable*, %Callable** %19 - %21 = call %Callable* @__quantum__rt__callable_copy(%Callable* %20, i1 false) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %21, i64 1) - call void @__quantum__rt__callable_make_controlled(%Callable* %21) - call void @__quantum__rt__callable_invoke(%Callable* %21, %Tuple* %15, %Tuple* %result-tuple) - call void @__quantum__rt__tuple_update_reference_count(%Tuple* %10, i64 -1) - call void @__quantum__rt__tuple_update_reference_count(%Tuple* %15, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %21, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %21, i64 -1) - ret void -} - -define void @Lifted__PartialApplication__1__ctladj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Array*, %Qubit* }* - %1 = getelementptr { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i64 0, i32 0 - %2 = getelementptr { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i64 0, i32 1 - %3 = load %Array*, %Array** %1 - %4 = load %Qubit*, %Qubit** %2 - %5 = bitcast %Tuple* %capture-tuple to { %Callable*, i2, double }* - %6 = getelementptr { %Callable*, i2, double }, { %Callable*, i2, double }* %5, i64 0, i32 1 - %7 = load i2, i2* %6 - %8 = getelementptr { %Callable*, i2, double }, { %Callable*, i2, double }* %5, i64 0, i32 2 - %9 = load double, double* %8 - %10 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ i2, double, %Qubit* }* getelementptr ({ i2, double, %Qubit* }, { i2, double, %Qubit* }* null, i32 1) to i64)) - %11 = bitcast %Tuple* %10 to { i2, double, %Qubit* }* - %12 = getelementptr { i2, double, %Qubit* }, { i2, double, %Qubit* }* %11, i64 0, i32 0 - %13 = getelementptr { i2, double, %Qubit* }, { i2, double, %Qubit* }* %11, i64 0, i32 1 - %14 = getelementptr { i2, double, %Qubit* }, { i2, double, %Qubit* }* %11, i64 0, i32 2 - store i2 %7, i2* %12 - store double %9, double* %13 - store %Qubit* %4, %Qubit** %14 - %15 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) - %16 = bitcast %Tuple* %15 to { %Array*, { i2, double, %Qubit* }* }* - %17 = getelementptr { %Array*, { i2, double, %Qubit* }* }, { %Array*, { i2, double, %Qubit* }* }* %16, i64 0, i32 0 - %18 = getelementptr { %Array*, { i2, double, %Qubit* }* }, { %Array*, { i2, double, %Qubit* }* }* %16, i64 0, i32 1 - store %Array* %3, %Array** %17 - store { i2, double, %Qubit* }* %11, { i2, double, %Qubit* }** %18 - %19 = getelementptr { %Callable*, i2, double }, { %Callable*, i2, double }* %5, i64 0, i32 0 - %20 = load %Callable*, %Callable** %19 - %21 = call %Callable* @__quantum__rt__callable_copy(%Callable* %20, i1 false) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %21, i64 1) - call void @__quantum__rt__callable_make_adjoint(%Callable* %21) - call void @__quantum__rt__callable_make_controlled(%Callable* %21) - call void @__quantum__rt__callable_invoke(%Callable* %21, %Tuple* %15, %Tuple* %result-tuple) - call void @__quantum__rt__tuple_update_reference_count(%Tuple* %10, i64 -1) - call void @__quantum__rt__tuple_update_reference_count(%Tuple* %15, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %21, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %21, i64 -1) - ret void -} - -define void @MemoryManagement__1__RefCount(%Tuple* %capture-tuple, i64 %count-change) { -entry: - %0 = bitcast %Tuple* %capture-tuple to { %Callable*, i2, double }* - %1 = getelementptr { %Callable*, i2, double }, { %Callable*, i2, double }* %0, i64 0, i32 0 - %2 = load %Callable*, %Callable** %1 - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %2, i64 %count-change) - call void @__quantum__rt__callable_update_reference_count(%Callable* %2, i64 %count-change) - call void @__quantum__rt__tuple_update_reference_count(%Tuple* %capture-tuple, i64 %count-change) - ret void -} - -define void @MemoryManagement__1__AliasCount(%Tuple* %capture-tuple, i64 %count-change) { -entry: - %0 = bitcast %Tuple* %capture-tuple to { %Callable*, i2, double }* - %1 = getelementptr { %Callable*, i2, double }, { %Callable*, i2, double }* %0, i64 0, i32 0 - %2 = load %Callable*, %Callable** %1 - call void @__quantum__rt__callable_memory_management(i32 1, %Callable* %2, i64 %count-change) - call void @__quantum__rt__callable_update_alias_count(%Callable* %2, i64 %count-change) - call void @__quantum__rt__tuple_update_alias_count(%Tuple* %capture-tuple, i64 %count-change) - ret void -} - -declare void @__quantum__rt__tuple_update_alias_count(%Tuple*, i64) - -attributes #0 = { "EntryPoint" } diff --git a/src/QirRuntime/test/QIR-dynamic/qir-test-random-lnx.ll b/src/QirRuntime/test/QIR-dynamic/qir-test-random-lnx.ll deleted file mode 100644 index cccc97ec31d..00000000000 --- a/src/QirRuntime/test/QIR-dynamic/qir-test-random-lnx.ll +++ /dev/null @@ -1,142 +0,0 @@ - -%Result = type opaque -%Range = type { i64, i64, i64 } -%Qubit = type opaque -%Array = type opaque - -@ResultZero = external global %Result* -@ResultOne = external global %Result* -@PauliI = constant i2 0 -@PauliX = constant i2 1 -@PauliY = constant i2 -1 -@PauliZ = constant i2 -2 -@EmptyRange = internal constant %Range { i64 0, i64 1, i64 -1 } - -@Microsoft__Quantum__Testing__QIR__QuantumRandomNumberGenerator = alias i64 (), i64 ()* @Microsoft__Quantum__Testing__QIR__QuantumRandomNumberGenerator__body - -define %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %qb) { -entry: - %bases__inline__1 = call %Array* @__quantum__rt__array_create_1d(i32 1, i64 1) - %0 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %bases__inline__1, i64 0) - %1 = bitcast i8* %0 to i2* - %2 = load i2, i2* @PauliZ - store i2 %2, i2* %1 - call void @__quantum__rt__array_update_alias_count(%Array* %bases__inline__1, i64 1) - %qubits__inline__1 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) - %3 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qubits__inline__1, i64 0) - %4 = bitcast i8* %3 to %Qubit** - store %Qubit* %qb, %Qubit** %4 - call void @__quantum__rt__array_update_alias_count(%Array* %qubits__inline__1, i64 1) - %5 = call %Result* @__quantum__qis__measure__body(%Array* %bases__inline__1, %Array* %qubits__inline__1) - call void @__quantum__rt__array_update_alias_count(%Array* %bases__inline__1, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits__inline__1, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %bases__inline__1, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %qubits__inline__1, i64 -1) - ret %Result* %5 -} - -declare %Array* @__quantum__rt__array_create_1d(i32, i64) - -declare i8* @__quantum__rt__array_get_element_ptr_1d(%Array*, i64) - -declare void @__quantum__rt__array_update_alias_count(%Array*, i64) - -declare %Result* @__quantum__qis__measure__body(%Array*, %Array*) - -declare void @__quantum__rt__array_update_reference_count(%Array*, i64) - -define %Result* @Microsoft__Quantum__Intrinsic__Measure__body(%Array* %bases, %Array* %qubits) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %bases, i64 1) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 1) - %0 = call %Result* @__quantum__qis__measure__body(%Array* %bases, %Array* %qubits) - call void @__quantum__rt__array_update_alias_count(%Array* %bases, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 -1) - ret %Result* %0 -} - -define void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %qb) { -entry: - call void @__quantum__qis__h__body(%Qubit* %qb) - ret void -} - -declare void @__quantum__qis__h__body(%Qubit*) - -define void @Microsoft__Quantum__Intrinsic__H__adj(%Qubit* %qb) { -entry: - call void @__quantum__qis__h__body(%Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__H__ctl(%Array* %__controlQubits__, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 1) - call void @__quantum__qis__h__ctl(%Array* %__controlQubits__, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 -1) - ret void -} - -declare void @__quantum__qis__h__ctl(%Array*, %Qubit*) - -define void @Microsoft__Quantum__Intrinsic__H__ctladj(%Array* %__controlQubits__, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 1) - call void @__quantum__qis__h__ctl(%Array* %__controlQubits__, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 -1) - ret void -} - -define i64 @Microsoft__Quantum__Testing__QIR__QuantumRandomNumberGenerator__body() #0 { -entry: - %randomNumber = alloca i64 - store i64 0, i64* %randomNumber - br label %header__1 - -header__1: ; preds = %exiting__1, %entry - %i = phi i64 [ 1, %entry ], [ %8, %exiting__1 ] - %0 = icmp sle i64 %i, 64 - br i1 %0, label %body__1, label %exit__1 - -body__1: ; preds = %header__1 - %q = call %Qubit* @__quantum__rt__qubit_allocate() - call void @__quantum__qis__h__body(%Qubit* %q) - %1 = load i64, i64* %randomNumber - %2 = shl i64 %1, 1 - store i64 %2, i64* %randomNumber - %3 = call %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %q) - %4 = load %Result*, %Result** @ResultOne - %5 = call i1 @__quantum__rt__result_equal(%Result* %3, %Result* %4) - br i1 %5, label %then0__1, label %continue__1 - -then0__1: ; preds = %body__1 - %6 = load i64, i64* %randomNumber - %7 = add i64 %6, 1 - store i64 %7, i64* %randomNumber - br label %continue__1 - -continue__1: ; preds = %then0__1, %body__1 - call void @__quantum__rt__qubit_release(%Qubit* %q) - call void @__quantum__rt__result_update_reference_count(%Result* %3, i64 -1) - br label %exiting__1 - -exiting__1: ; preds = %continue__1 - %8 = add i64 %i, 1 - br label %header__1 - -exit__1: ; preds = %header__1 - %9 = load i64, i64* %randomNumber - ret i64 %9 -} - -declare %Qubit* @__quantum__rt__qubit_allocate() - -declare %Array* @__quantum__rt__qubit_allocate_array(i64) - -declare i1 @__quantum__rt__result_equal(%Result*, %Result*) - -declare void @__quantum__rt__qubit_release(%Qubit*) - -declare void @__quantum__rt__result_update_reference_count(%Result*, i64) - -attributes #0 = { "EntryPoint" } diff --git a/src/QirRuntime/test/QIR-dynamic/qir-test-random-win.ll b/src/QirRuntime/test/QIR-dynamic/qir-test-random-win.ll deleted file mode 100644 index d83a3f082e4..00000000000 --- a/src/QirRuntime/test/QIR-dynamic/qir-test-random-win.ll +++ /dev/null @@ -1,142 +0,0 @@ - -%Result = type opaque -%Range = type { i64, i64, i64 } -%Qubit = type opaque -%Array = type opaque - -@ResultZero = external dllimport global %Result* -@ResultOne = external dllimport global %Result* -@PauliI = constant i2 0 -@PauliX = constant i2 1 -@PauliY = constant i2 -1 -@PauliZ = constant i2 -2 -@EmptyRange = internal constant %Range { i64 0, i64 1, i64 -1 } - -@Microsoft__Quantum__Testing__QIR__QuantumRandomNumberGenerator = alias i64 (), i64 ()* @Microsoft__Quantum__Testing__QIR__QuantumRandomNumberGenerator__body - -define %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %qb) { -entry: - %bases__inline__1 = call %Array* @__quantum__rt__array_create_1d(i32 1, i64 1) - %0 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %bases__inline__1, i64 0) - %1 = bitcast i8* %0 to i2* - %2 = load i2, i2* @PauliZ - store i2 %2, i2* %1 - call void @__quantum__rt__array_update_alias_count(%Array* %bases__inline__1, i64 1) - %qubits__inline__1 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) - %3 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qubits__inline__1, i64 0) - %4 = bitcast i8* %3 to %Qubit** - store %Qubit* %qb, %Qubit** %4 - call void @__quantum__rt__array_update_alias_count(%Array* %qubits__inline__1, i64 1) - %5 = call %Result* @__quantum__qis__measure__body(%Array* %bases__inline__1, %Array* %qubits__inline__1) - call void @__quantum__rt__array_update_alias_count(%Array* %bases__inline__1, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits__inline__1, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %bases__inline__1, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %qubits__inline__1, i64 -1) - ret %Result* %5 -} - -declare %Array* @__quantum__rt__array_create_1d(i32, i64) - -declare i8* @__quantum__rt__array_get_element_ptr_1d(%Array*, i64) - -declare void @__quantum__rt__array_update_alias_count(%Array*, i64) - -declare %Result* @__quantum__qis__measure__body(%Array*, %Array*) - -declare void @__quantum__rt__array_update_reference_count(%Array*, i64) - -define %Result* @Microsoft__Quantum__Intrinsic__Measure__body(%Array* %bases, %Array* %qubits) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %bases, i64 1) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 1) - %0 = call %Result* @__quantum__qis__measure__body(%Array* %bases, %Array* %qubits) - call void @__quantum__rt__array_update_alias_count(%Array* %bases, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 -1) - ret %Result* %0 -} - -define void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %qb) { -entry: - call void @__quantum__qis__h__body(%Qubit* %qb) - ret void -} - -declare void @__quantum__qis__h__body(%Qubit*) - -define void @Microsoft__Quantum__Intrinsic__H__adj(%Qubit* %qb) { -entry: - call void @__quantum__qis__h__body(%Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__H__ctl(%Array* %__controlQubits__, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 1) - call void @__quantum__qis__h__ctl(%Array* %__controlQubits__, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 -1) - ret void -} - -declare void @__quantum__qis__h__ctl(%Array*, %Qubit*) - -define void @Microsoft__Quantum__Intrinsic__H__ctladj(%Array* %__controlQubits__, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 1) - call void @__quantum__qis__h__ctl(%Array* %__controlQubits__, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 -1) - ret void -} - -define i64 @Microsoft__Quantum__Testing__QIR__QuantumRandomNumberGenerator__body() #0 { -entry: - %randomNumber = alloca i64 - store i64 0, i64* %randomNumber - br label %header__1 - -header__1: ; preds = %exiting__1, %entry - %i = phi i64 [ 1, %entry ], [ %8, %exiting__1 ] - %0 = icmp sle i64 %i, 64 - br i1 %0, label %body__1, label %exit__1 - -body__1: ; preds = %header__1 - %q = call %Qubit* @__quantum__rt__qubit_allocate() - call void @__quantum__qis__h__body(%Qubit* %q) - %1 = load i64, i64* %randomNumber - %2 = shl i64 %1, 1 - store i64 %2, i64* %randomNumber - %3 = call %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %q) - %4 = load %Result*, %Result** @ResultOne - %5 = call i1 @__quantum__rt__result_equal(%Result* %3, %Result* %4) - br i1 %5, label %then0__1, label %continue__1 - -then0__1: ; preds = %body__1 - %6 = load i64, i64* %randomNumber - %7 = add i64 %6, 1 - store i64 %7, i64* %randomNumber - br label %continue__1 - -continue__1: ; preds = %then0__1, %body__1 - call void @__quantum__rt__qubit_release(%Qubit* %q) - call void @__quantum__rt__result_update_reference_count(%Result* %3, i64 -1) - br label %exiting__1 - -exiting__1: ; preds = %continue__1 - %8 = add i64 %i, 1 - br label %header__1 - -exit__1: ; preds = %header__1 - %9 = load i64, i64* %randomNumber - ret i64 %9 -} - -declare %Qubit* @__quantum__rt__qubit_allocate() - -declare %Array* @__quantum__rt__qubit_allocate_array(i64) - -declare i1 @__quantum__rt__result_equal(%Result*, %Result*) - -declare void @__quantum__rt__qubit_release(%Qubit*) - -declare void @__quantum__rt__result_update_reference_count(%Result*, i64) - -attributes #0 = { "EntryPoint" } diff --git a/src/QirRuntime/test/QIR-static/CMakeLists.txt b/src/QirRuntime/test/QIR-static/CMakeLists.txt deleted file mode 100644 index 7e6c2f1234e..00000000000 --- a/src/QirRuntime/test/QIR-static/CMakeLists.txt +++ /dev/null @@ -1,49 +0,0 @@ -# compile test ll files into a library - -set(TEST_FILES - qir-test-noqsharp - qir-gen -) - -foreach(file ${TEST_FILES}) - compile_from_qir(${file} "") # don't create a target per file - list(APPEND QIR_TESTS_LIBS ${QIR_UTILITY_LIB}) -endforeach() - -add_custom_target(qir_static_test_lib DEPENDS ${QIR_TESTS_LIBS}) - -#============================================================================== -# The executable target for QIR tests triggers the custom actions to compile ll files -# -add_executable(qir-static-tests - qir-driver.cpp - qir-test-conditionals.cpp - qir-test-math.cpp - qir-test-strings.cpp - qir-test-ouput.cpp - qir-test-other.cpp -) - -target_link_libraries(qir-static-tests PUBLIC - ${QIR_TESTS_LIBS} - ${QIR_BRIDGE_UTILITY_LIB} - ${QSHARP_FOUNDATION_BRIDGE_QIS_UTILITY_LIB} - ${QSHARP_CORE_BRIDGE_QIS_UTILITY_LIB} - qir-rt-support - qsharp-foundation-qis-support - qsharp-core-qis-support - simulators -) - -target_include_directories(qir-static-tests PUBLIC - "${test_includes}" - "${public_includes}" - "${PROJECT_SOURCE_DIR}/lib/QIR" - "${PROJECT_SOURCE_DIR}/lib/QSharpFoundation" -) -target_compile_definitions(qir-static-tests PRIVATE EXPORT_QIR_API) -add_dependencies(qir-static-tests qir_static_test_lib) - -install(TARGETS qir-static-tests RUNTIME DESTINATION "${CMAKE_BINARY_DIR}/bin") -add_unit_test(qir-static-tests) - diff --git a/src/QirRuntime/test/QIR-static/qsharp/main.cs b/src/QirRuntime/test/QIR-static/qsharp/main.cs deleted file mode 100644 index 3e0cec7acae..00000000000 --- a/src/QirRuntime/test/QIR-static/qsharp/main.cs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -// Currently, compiling to QIR has to suppress C# generation but then we need to provide Main function ourselves. -namespace CompilerWorkaround -{ - class Program - { - static void Main(string[] args) - { - } - } -} \ No newline at end of file diff --git a/src/QirRuntime/test/QIR-tracer/CMakeLists.txt b/src/QirRuntime/test/QIR-tracer/CMakeLists.txt deleted file mode 100644 index fb6ab5bd850..00000000000 --- a/src/QirRuntime/test/QIR-tracer/CMakeLists.txt +++ /dev/null @@ -1,42 +0,0 @@ -if (WIN32) - set(TEST_FILES - tracer-qir-win - ) -else() - set(TEST_FILES - tracer-qir-lnx - ) -endif() - -foreach(file ${TEST_FILES}) - compile_from_qir(${file} "") # don't create a target per file - list(APPEND QIR_TESTS_LIBS ${QIR_UTILITY_LIB}) -endforeach() - -add_custom_target(tracer_qir_test_lib DEPENDS ${QIR_TESTS_LIBS}) - -#============================================================================== -# The executable target for QIR tests triggers the custom actions to compile ll files -# -add_executable(qir-tracer-tests - qir-tracer-driver.cpp - tracer-config.cpp -) - -target_link_libraries(qir-tracer-tests PUBLIC - ${QIR_TESTS_LIBS} - "-L${CMAKE_BINARY_DIR}/lib/QIR" - -lMicrosoft.Quantum.Qir.Runtime - "-L${CMAKE_BINARY_DIR}/lib/Tracer" - -lMicrosoft.Quantum.Qir.Tracer -) - -target_include_directories(qir-tracer-tests PUBLIC - "${test_includes}" - "${public_includes}" - "${PROJECT_SOURCE_DIR}/lib/Tracer" # TODO: Remove this when tracer api is put into public headers. -) -add_dependencies(qir-tracer-tests tracer_qir_test_lib) - -install(TARGETS qir-tracer-tests RUNTIME DESTINATION "${CMAKE_BINARY_DIR}/bin") -add_unit_test(qir-tracer-tests) diff --git a/src/QirRuntime/test/QIR-tracer/tracer-qir-lnx.ll b/src/QirRuntime/test/QIR-tracer/tracer-qir-lnx.ll deleted file mode 100644 index ab33750832b..00000000000 --- a/src/QirRuntime/test/QIR-tracer/tracer-qir-lnx.ll +++ /dev/null @@ -1,2019 +0,0 @@ - -%Result = type opaque -%Range = type { i64, i64, i64 } -%Tuple = type opaque -%Array = type opaque -%Callable = type opaque -%Qubit = type opaque -%String = type opaque - -@ResultZero = external global %Result* -@ResultOne = external global %Result* -@PauliI = constant i2 0 -@PauliX = constant i2 1 -@PauliY = constant i2 -1 -@PauliZ = constant i2 -2 -@EmptyRange = internal constant %Range { i64 0, i64 1, i64 -1 } -@Microsoft__Quantum__Testing__Tracer__Delay = constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Testing__Tracer__Delay__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* null, void (%Tuple*, %Tuple*, %Tuple*)* null, void (%Tuple*, %Tuple*, %Tuple*)* null] -@Microsoft__Quantum__Intrinsic__X = constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__X__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__X__adj__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__X__ctl__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__X__ctladj__wrapper] -@PartialApplication__1 = constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Lifted__PartialApplication__1__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* null, void (%Tuple*, %Tuple*, %Tuple*)* null, void (%Tuple*, %Tuple*, %Tuple*)* null] -@MemoryManagement__1 = constant [2 x void (%Tuple*, i64)*] [void (%Tuple*, i64)* @MemoryManagement__1__RefCount, void (%Tuple*, i64)* @MemoryManagement__1__AliasCount] -@Microsoft__Quantum__Intrinsic__Y = constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Y__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Y__adj__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Y__ctl__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Y__ctladj__wrapper] -@PartialApplication__2 = constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Lifted__PartialApplication__2__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* null, void (%Tuple*, %Tuple*, %Tuple*)* null, void (%Tuple*, %Tuple*, %Tuple*)* null] -@Microsoft__Quantum__Intrinsic__Z = constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Z__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Z__adj__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Z__ctl__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Z__ctladj__wrapper] -@PartialApplication__3 = constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Lifted__PartialApplication__3__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* null, void (%Tuple*, %Tuple*, %Tuple*)* null, void (%Tuple*, %Tuple*, %Tuple*)* null] -@Microsoft__Quantum__Intrinsic__S = constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__S__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__S__adj__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__S__ctl__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__S__ctladj__wrapper] -@PartialApplication__4 = constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Lifted__PartialApplication__4__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* null, void (%Tuple*, %Tuple*, %Tuple*)* null, void (%Tuple*, %Tuple*, %Tuple*)* null] -@MemoryManagement__2 = constant [2 x void (%Tuple*, i64)*] [void (%Tuple*, i64)* @MemoryManagement__2__RefCount, void (%Tuple*, i64)* @MemoryManagement__2__AliasCount] - -define void @Microsoft__Quantum__Intrinsic__ApplyConditionallyIntrinsic__body(%Array* %measurementResults, %Array* %resultsValues, %Callable* %onEqualOp, %Callable* %onNonEqualOp) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %measurementResults, i64 1) - call void @__quantum__rt__array_update_alias_count(%Array* %resultsValues, i64 1) - call void @__quantum__rt__callable_memory_management(i32 1, %Callable* %onEqualOp, i64 1) - call void @__quantum__rt__callable_update_alias_count(%Callable* %onEqualOp, i64 1) - call void @__quantum__rt__callable_memory_management(i32 1, %Callable* %onNonEqualOp, i64 1) - call void @__quantum__rt__callable_update_alias_count(%Callable* %onNonEqualOp, i64 1) - call void @__quantum__qis__apply_conditionally(%Array* %measurementResults, %Array* %resultsValues, %Callable* %onEqualOp, %Callable* %onNonEqualOp) - call void @__quantum__rt__array_update_alias_count(%Array* %measurementResults, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %resultsValues, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 1, %Callable* %onEqualOp, i64 -1) - call void @__quantum__rt__callable_update_alias_count(%Callable* %onEqualOp, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 1, %Callable* %onNonEqualOp, i64 -1) - call void @__quantum__rt__callable_update_alias_count(%Callable* %onNonEqualOp, i64 -1) - ret void -} - -declare void @__quantum__rt__array_update_alias_count(%Array*, i64) - -declare void @__quantum__rt__callable_memory_management(i32, %Callable*, i64) - -declare void @__quantum__rt__callable_update_alias_count(%Callable*, i64) - -declare void @__quantum__qis__apply_conditionally(%Array*, %Array*, %Callable*, %Callable*) - -define void @Microsoft__Quantum__Intrinsic__ApplyIfElseIntrinsic__body(%Result* %measurementResult, %Callable* %onResultZeroOp, %Callable* %onResultOneOp) { -entry: - call void @__quantum__rt__callable_memory_management(i32 1, %Callable* %onResultZeroOp, i64 1) - call void @__quantum__rt__callable_update_alias_count(%Callable* %onResultZeroOp, i64 1) - call void @__quantum__rt__callable_memory_management(i32 1, %Callable* %onResultOneOp, i64 1) - call void @__quantum__rt__callable_update_alias_count(%Callable* %onResultOneOp, i64 1) - %0 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) - %1 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %0, i64 0) - %2 = bitcast i8* %1 to %Result** - store %Result* %measurementResult, %Result** %2 - %3 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) - %4 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %3, i64 0) - %5 = bitcast i8* %4 to %Result** - %6 = load %Result*, %Result** @ResultZero - store %Result* %6, %Result** %5 - call void @__quantum__qis__apply_conditionally(%Array* %0, %Array* %3, %Callable* %onResultZeroOp, %Callable* %onResultOneOp) - call void @__quantum__rt__result_update_reference_count(%Result* %measurementResult, i64 1) - call void @__quantum__rt__result_update_reference_count(%Result* %6, i64 1) - call void @__quantum__rt__callable_memory_management(i32 1, %Callable* %onResultZeroOp, i64 -1) - call void @__quantum__rt__callable_update_alias_count(%Callable* %onResultZeroOp, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 1, %Callable* %onResultOneOp, i64 -1) - call void @__quantum__rt__callable_update_alias_count(%Callable* %onResultOneOp, i64 -1) - br label %header__1 - -header__1: ; preds = %exiting__1, %entry - %7 = phi i64 [ 0, %entry ], [ %12, %exiting__1 ] - %8 = icmp sle i64 %7, 0 - br i1 %8, label %body__1, label %exit__1 - -body__1: ; preds = %header__1 - %9 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %0, i64 %7) - %10 = bitcast i8* %9 to %Result** - %11 = load %Result*, %Result** %10 - call void @__quantum__rt__result_update_reference_count(%Result* %11, i64 -1) - br label %exiting__1 - -exiting__1: ; preds = %body__1 - %12 = add i64 %7, 1 - br label %header__1 - -exit__1: ; preds = %header__1 - call void @__quantum__rt__array_update_reference_count(%Array* %0, i64 -1) - br label %header__2 - -header__2: ; preds = %exiting__2, %exit__1 - %13 = phi i64 [ 0, %exit__1 ], [ %18, %exiting__2 ] - %14 = icmp sle i64 %13, 0 - br i1 %14, label %body__2, label %exit__2 - -body__2: ; preds = %header__2 - %15 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %3, i64 %13) - %16 = bitcast i8* %15 to %Result** - %17 = load %Result*, %Result** %16 - call void @__quantum__rt__result_update_reference_count(%Result* %17, i64 -1) - br label %exiting__2 - -exiting__2: ; preds = %body__2 - %18 = add i64 %13, 1 - br label %header__2 - -exit__2: ; preds = %header__2 - call void @__quantum__rt__array_update_reference_count(%Array* %3, i64 -1) - ret void -} - -declare %Array* @__quantum__rt__array_create_1d(i32, i64) - -declare i8* @__quantum__rt__array_get_element_ptr_1d(%Array*, i64) - -declare void @__quantum__rt__result_update_reference_count(%Result*, i64) - -declare void @__quantum__rt__array_update_reference_count(%Array*, i64) - -define void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %control, %Qubit* %target) { -entry: - %ctls = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) - %0 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 0) - %1 = bitcast i8* %0 to %Qubit** - store %Qubit* %control, %Qubit** %1 - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - br i1 true, label %then0__1, label %else__1 - -then0__1: ; preds = %entry - call void @__quantum__qis__single_qubit_op_ctl(i64 1, i64 1, %Array* %ctls, %Qubit* %target) - br label %continue__1 - -else__1: ; preds = %entry - call void @__quantum__qis__single_qubit_op_ctl(i64 2, i64 1, %Array* %ctls, %Qubit* %target) - br label %continue__1 - -continue__1: ; preds = %else__1, %then0__1 - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i64 -1) - ret void -} - -declare void @__quantum__qis__single_qubit_op_ctl(i64, i64, %Array*, %Qubit*) - -define void @Microsoft__Quantum__Intrinsic__CNOT__adj(%Qubit* %control, %Qubit* %target) { -entry: - call void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %control, %Qubit* %target) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__CNOT__ctl(%Array* %ctls, { %Qubit*, %Qubit* }* %0) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - %1 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %0, i32 0, i32 0 - %control = load %Qubit*, %Qubit** %1 - %2 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %0, i32 0, i32 1 - %target = load %Qubit*, %Qubit** %2 - %3 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) - %4 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %3, i64 0) - %5 = bitcast i8* %4 to %Qubit** - store %Qubit* %control, %Qubit** %5 - %ctls__1 = call %Array* @__quantum__rt__array_concatenate(%Array* %ctls, %Array* %3) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls__1, i64 1) - %6 = call i64 @__quantum__rt__array_get_size_1d(%Array* %ctls__1) - %7 = icmp eq i64 %6, 1 - br i1 %7, label %then0__1, label %else__1 - -then0__1: ; preds = %entry - call void @__quantum__qis__single_qubit_op_ctl(i64 1, i64 1, %Array* %ctls__1, %Qubit* %target) - br label %continue__1 - -else__1: ; preds = %entry - call void @__quantum__qis__single_qubit_op_ctl(i64 2, i64 1, %Array* %ctls__1, %Qubit* %target) - br label %continue__1 - -continue__1: ; preds = %else__1, %then0__1 - call void @__quantum__rt__array_update_alias_count(%Array* %ctls__1, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %3, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %ctls__1, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -declare %Array* @__quantum__rt__array_concatenate(%Array*, %Array*) - -declare i64 @__quantum__rt__array_get_size_1d(%Array*) - -define void @Microsoft__Quantum__Intrinsic__CNOT__ctladj(%Array* %__controlQubits__, { %Qubit*, %Qubit* }* %0) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 1) - %1 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %0, i32 0, i32 0 - %control = load %Qubit*, %Qubit** %1 - %2 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %0, i32 0, i32 1 - %target = load %Qubit*, %Qubit** %2 - %3 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) - %4 = bitcast %Tuple* %3 to { %Qubit*, %Qubit* }* - %5 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %4, i32 0, i32 0 - %6 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %4, i32 0, i32 1 - store %Qubit* %control, %Qubit** %5 - store %Qubit* %target, %Qubit** %6 - call void @Microsoft__Quantum__Intrinsic__CNOT__ctl(%Array* %__controlQubits__, { %Qubit*, %Qubit* }* %4) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 -1) - call void @__quantum__rt__tuple_update_reference_count(%Tuple* %3, i64 -1) - ret void -} - -declare %Tuple* @__quantum__rt__tuple_create(i64) - -declare void @__quantum__rt__tuple_update_reference_count(%Tuple*, i64) - -define void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 9, i64 1, %Qubit* %qb) - ret void -} - -declare void @__quantum__qis__single_qubit_op(i64, i64, %Qubit*) - -define void @Microsoft__Quantum__Intrinsic__H__adj(%Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 9, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__H__ctl(%Array* %ctls, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - call void @__quantum__qis__single_qubit_op_ctl(i64 10, i64 1, %Array* %ctls, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__H__ctladj(%Array* %__controlQubits__, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 1) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 1) - call void @__quantum__qis__single_qubit_op_ctl(i64 10, i64 1, %Array* %__controlQubits__, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 -1) - ret void -} - -define %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %qb) { -entry: - %0 = call %Result* @__quantum__qis__single_qubit_measure(i64 100, i64 1, %Qubit* %qb) - ret %Result* %0 -} - -declare %Result* @__quantum__qis__single_qubit_measure(i64, i64, %Qubit*) - -define %Result* @Microsoft__Quantum__Intrinsic__Measure__body(%Array* %paulis, %Array* %qubits) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %paulis, i64 1) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 1) - %0 = load %Result*, %Result** @ResultOne - %res = alloca %Result* - store %Result* %0, %Result** %res - call void @__quantum__rt__result_update_reference_count(%Result* %0, i64 1) - %haveY = alloca i1 - store i1 false, i1* %haveY - %1 = call i64 @__quantum__rt__array_get_size_1d(%Array* %paulis) - %2 = sub i64 %1, 1 - br label %header__1 - -header__1: ; preds = %exiting__1, %entry - %i = phi i64 [ 0, %entry ], [ %15, %exiting__1 ] - %3 = icmp sle i64 %i, %2 - br i1 %3, label %body__1, label %exit__1 - -body__1: ; preds = %header__1 - %4 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 %i) - %5 = bitcast i8* %4 to i2* - %6 = load i2, i2* %5 - %7 = load i2, i2* @PauliY - %8 = icmp eq i2 %6, %7 - %9 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 %i) - %10 = bitcast i8* %9 to i2* - %11 = load i2, i2* %10 - %12 = load i2, i2* @PauliI - %13 = icmp eq i2 %11, %12 - %14 = or i1 %8, %13 - br i1 %14, label %then0__1, label %continue__1 - -then0__1: ; preds = %body__1 - store i1 true, i1* %haveY - br label %continue__1 - -continue__1: ; preds = %then0__1, %body__1 - br label %exiting__1 - -exiting__1: ; preds = %continue__1 - %15 = add i64 %i, 1 - br label %header__1 - -exit__1: ; preds = %header__1 - %16 = load i1, i1* %haveY - br i1 %16, label %then0__2, label %test1__1 - -then0__2: ; preds = %exit__1 - %17 = call %Result* @__quantum__qis__joint_measure(i64 106, i64 1, %Array* %qubits) - call void @__quantum__rt__result_update_reference_count(%Result* %17, i64 1) - store %Result* %17, %Result** %res - call void @__quantum__rt__result_update_reference_count(%Result* %17, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %0, i64 -1) - br label %continue__2 - -test1__1: ; preds = %exit__1 - %18 = icmp sgt i64 %1, 2 - br i1 %18, label %then1__1, label %test2__1 - -then1__1: ; preds = %test1__1 - %19 = call %Result* @__quantum__qis__joint_measure(i64 107, i64 1, %Array* %qubits) - call void @__quantum__rt__result_update_reference_count(%Result* %19, i64 1) - %20 = load %Result*, %Result** %res - store %Result* %19, %Result** %res - call void @__quantum__rt__result_update_reference_count(%Result* %19, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %20, i64 -1) - br label %continue__2 - -test2__1: ; preds = %test1__1 - %21 = icmp eq i64 %1, 1 - br i1 %21, label %then2__1, label %test3__1 - -then2__1: ; preds = %test2__1 - %22 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 0) - %23 = bitcast i8* %22 to i2* - %24 = load i2, i2* %23 - %25 = load i2, i2* @PauliX - %26 = icmp eq i2 %24, %25 - br i1 %26, label %then0__3, label %else__1 - -then0__3: ; preds = %then2__1 - %27 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qubits, i64 0) - %28 = bitcast i8* %27 to %Qubit** - %qb = load %Qubit*, %Qubit** %28 - %29 = call %Result* @__quantum__qis__single_qubit_measure(i64 101, i64 1, %Qubit* %qb) - call void @__quantum__rt__result_update_reference_count(%Result* %29, i64 1) - %30 = load %Result*, %Result** %res - store %Result* %29, %Result** %res - call void @__quantum__rt__result_update_reference_count(%Result* %29, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %30, i64 -1) - br label %continue__3 - -else__1: ; preds = %then2__1 - %31 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qubits, i64 0) - %32 = bitcast i8* %31 to %Qubit** - %qb__1 = load %Qubit*, %Qubit** %32 - %33 = call %Result* @__quantum__qis__single_qubit_measure(i64 100, i64 1, %Qubit* %qb__1) - call void @__quantum__rt__result_update_reference_count(%Result* %33, i64 1) - %34 = load %Result*, %Result** %res - store %Result* %33, %Result** %res - call void @__quantum__rt__result_update_reference_count(%Result* %33, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %34, i64 -1) - br label %continue__3 - -continue__3: ; preds = %else__1, %then0__3 - br label %continue__2 - -test3__1: ; preds = %test2__1 - %35 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 0) - %36 = bitcast i8* %35 to i2* - %37 = load i2, i2* %36 - %38 = load i2, i2* @PauliX - %39 = icmp eq i2 %37, %38 - %40 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 1) - %41 = bitcast i8* %40 to i2* - %42 = load i2, i2* %41 - %43 = load i2, i2* @PauliX - %44 = icmp eq i2 %42, %43 - %45 = and i1 %39, %44 - br i1 %45, label %then3__1, label %test4__1 - -then3__1: ; preds = %test3__1 - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 1) - %46 = call %Result* @__quantum__qis__joint_measure(i64 105, i64 1, %Array* %qubits) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %46, i64 1) - %47 = load %Result*, %Result** %res - store %Result* %46, %Result** %res - call void @__quantum__rt__result_update_reference_count(%Result* %46, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %47, i64 -1) - br label %continue__2 - -test4__1: ; preds = %test3__1 - %48 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 0) - %49 = bitcast i8* %48 to i2* - %50 = load i2, i2* %49 - %51 = load i2, i2* @PauliX - %52 = icmp eq i2 %50, %51 - %53 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 1) - %54 = bitcast i8* %53 to i2* - %55 = load i2, i2* %54 - %56 = load i2, i2* @PauliZ - %57 = icmp eq i2 %55, %56 - %58 = and i1 %52, %57 - br i1 %58, label %then4__1, label %test5__1 - -then4__1: ; preds = %test4__1 - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 1) - %59 = call %Result* @__quantum__qis__joint_measure(i64 103, i64 1, %Array* %qubits) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %59, i64 1) - %60 = load %Result*, %Result** %res - store %Result* %59, %Result** %res - call void @__quantum__rt__result_update_reference_count(%Result* %59, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %60, i64 -1) - br label %continue__2 - -test5__1: ; preds = %test4__1 - %61 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 0) - %62 = bitcast i8* %61 to i2* - %63 = load i2, i2* %62 - %64 = load i2, i2* @PauliZ - %65 = icmp eq i2 %63, %64 - %66 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 1) - %67 = bitcast i8* %66 to i2* - %68 = load i2, i2* %67 - %69 = load i2, i2* @PauliX - %70 = icmp eq i2 %68, %69 - %71 = and i1 %65, %70 - br i1 %71, label %then5__1, label %test6__1 - -then5__1: ; preds = %test5__1 - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 1) - %72 = call %Result* @__quantum__qis__joint_measure(i64 104, i64 1, %Array* %qubits) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %72, i64 1) - %73 = load %Result*, %Result** %res - store %Result* %72, %Result** %res - call void @__quantum__rt__result_update_reference_count(%Result* %72, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %73, i64 -1) - br label %continue__2 - -test6__1: ; preds = %test5__1 - %74 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 0) - %75 = bitcast i8* %74 to i2* - %76 = load i2, i2* %75 - %77 = load i2, i2* @PauliZ - %78 = icmp eq i2 %76, %77 - %79 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 1) - %80 = bitcast i8* %79 to i2* - %81 = load i2, i2* %80 - %82 = load i2, i2* @PauliZ - %83 = icmp eq i2 %81, %82 - %84 = and i1 %78, %83 - br i1 %84, label %then6__1, label %continue__2 - -then6__1: ; preds = %test6__1 - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 1) - %85 = call %Result* @__quantum__qis__joint_measure(i64 102, i64 1, %Array* %qubits) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %85, i64 1) - %86 = load %Result*, %Result** %res - store %Result* %85, %Result** %res - call void @__quantum__rt__result_update_reference_count(%Result* %85, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %86, i64 -1) - br label %continue__2 - -continue__2: ; preds = %then6__1, %test6__1, %then5__1, %then4__1, %then3__1, %continue__3, %then1__1, %then0__2 - %87 = load %Result*, %Result** %res - call void @__quantum__rt__array_update_alias_count(%Array* %paulis, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 -1) - ret %Result* %87 -} - -declare %Result* @__quantum__qis__joint_measure(i64, i64, %Array*) - -define void @Microsoft__Quantum__Intrinsic__Rx__body(double %theta, %Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 19, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Rx__adj(double %theta, %Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 19, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Rx__ctl(%Array* %ctls, { double, %Qubit* }* %0) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - %1 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 0 - %theta = load double, double* %1 - %2 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 1 - %qb = load %Qubit*, %Qubit** %2 - call void @__quantum__qis__single_qubit_op_ctl(i64 20, i64 1, %Array* %ctls, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Rx__ctladj(%Array* %ctls, { double, %Qubit* }* %0) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - %1 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 0 - %theta = load double, double* %1 - %2 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 1 - %qb = load %Qubit*, %Qubit** %2 - call void @__quantum__qis__single_qubit_op_ctl(i64 20, i64 1, %Array* %ctls, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Ry__body(double %theta, %Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 21, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Ry__adj(double %theta, %Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 21, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Ry__ctl(%Array* %ctls, { double, %Qubit* }* %0) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - %1 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 0 - %theta = load double, double* %1 - %2 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 1 - %qb = load %Qubit*, %Qubit** %2 - call void @__quantum__qis__single_qubit_op_ctl(i64 22, i64 1, %Array* %ctls, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Ry__ctladj(%Array* %ctls, { double, %Qubit* }* %0) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - %1 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 0 - %theta = load double, double* %1 - %2 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 1 - %qb = load %Qubit*, %Qubit** %2 - call void @__quantum__qis__single_qubit_op_ctl(i64 22, i64 1, %Array* %ctls, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Rz__body(double %theta, %Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 23, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Rz__adj(double %theta, %Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 23, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Rz__ctl(%Array* %ctls, { double, %Qubit* }* %0) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - %1 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 0 - %theta = load double, double* %1 - %2 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 1 - %qb = load %Qubit*, %Qubit** %2 - call void @__quantum__qis__single_qubit_op_ctl(i64 24, i64 1, %Array* %ctls, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Rz__ctladj(%Array* %ctls, { double, %Qubit* }* %0) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - %1 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 0 - %theta = load double, double* %1 - %2 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 1 - %qb = load %Qubit*, %Qubit** %2 - call void @__quantum__qis__single_qubit_op_ctl(i64 24, i64 1, %Array* %ctls, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__S__body(%Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 15, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__S__adj(%Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 15, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__S__ctl(%Array* %ctls, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - call void @__quantum__qis__single_qubit_op_ctl(i64 16, i64 1, %Array* %ctls, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__S__ctladj(%Array* %ctls, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - call void @__quantum__qis__single_qubit_op_ctl(i64 16, i64 1, %Array* %ctls, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__T__body(%Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 11, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__T__adj(%Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 11, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__T__ctl(%Array* %ctls, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - call void @__quantum__qis__single_qubit_op_ctl(i64 12, i64 1, %Array* %ctls, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__T__ctladj(%Array* %ctls, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - call void @__quantum__qis__single_qubit_op_ctl(i64 12, i64 1, %Array* %ctls, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__X__body(%Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 0, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__X__adj(%Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 0, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__X__ctl(%Array* %ctls, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - %0 = call i64 @__quantum__rt__array_get_size_1d(%Array* %ctls) - %1 = icmp eq i64 %0, 1 - br i1 %1, label %then0__1, label %else__1 - -then0__1: ; preds = %entry - call void @__quantum__qis__single_qubit_op_ctl(i64 1, i64 1, %Array* %ctls, %Qubit* %qb) - br label %continue__1 - -else__1: ; preds = %entry - call void @__quantum__qis__single_qubit_op_ctl(i64 2, i64 1, %Array* %ctls, %Qubit* %qb) - br label %continue__1 - -continue__1: ; preds = %else__1, %then0__1 - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__X__ctladj(%Array* %__controlQubits__, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 1) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 1) - %0 = call i64 @__quantum__rt__array_get_size_1d(%Array* %__controlQubits__) - %1 = icmp eq i64 %0, 1 - br i1 %1, label %then0__1, label %else__1 - -then0__1: ; preds = %entry - call void @__quantum__qis__single_qubit_op_ctl(i64 1, i64 1, %Array* %__controlQubits__, %Qubit* %qb) - br label %continue__1 - -else__1: ; preds = %entry - call void @__quantum__qis__single_qubit_op_ctl(i64 2, i64 1, %Array* %__controlQubits__, %Qubit* %qb) - br label %continue__1 - -continue__1: ; preds = %else__1, %then0__1 - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Y__body(%Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 3, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Y__adj(%Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 3, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Y__ctl(%Array* %ctls, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - %0 = call i64 @__quantum__rt__array_get_size_1d(%Array* %ctls) - %1 = icmp eq i64 %0, 1 - br i1 %1, label %then0__1, label %else__1 - -then0__1: ; preds = %entry - call void @__quantum__qis__single_qubit_op_ctl(i64 4, i64 1, %Array* %ctls, %Qubit* %qb) - br label %continue__1 - -else__1: ; preds = %entry - call void @__quantum__qis__single_qubit_op_ctl(i64 5, i64 1, %Array* %ctls, %Qubit* %qb) - br label %continue__1 - -continue__1: ; preds = %else__1, %then0__1 - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Y__ctladj(%Array* %__controlQubits__, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 1) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 1) - %0 = call i64 @__quantum__rt__array_get_size_1d(%Array* %__controlQubits__) - %1 = icmp eq i64 %0, 1 - br i1 %1, label %then0__1, label %else__1 - -then0__1: ; preds = %entry - call void @__quantum__qis__single_qubit_op_ctl(i64 4, i64 1, %Array* %__controlQubits__, %Qubit* %qb) - br label %continue__1 - -else__1: ; preds = %entry - call void @__quantum__qis__single_qubit_op_ctl(i64 5, i64 1, %Array* %__controlQubits__, %Qubit* %qb) - br label %continue__1 - -continue__1: ; preds = %else__1, %then0__1 - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Z__body(%Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 6, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Z__adj(%Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 6, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Z__ctl(%Array* %ctls, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - %0 = call i64 @__quantum__rt__array_get_size_1d(%Array* %ctls) - %1 = icmp eq i64 %0, 1 - br i1 %1, label %then0__1, label %else__1 - -then0__1: ; preds = %entry - call void @__quantum__qis__single_qubit_op_ctl(i64 7, i64 1, %Array* %ctls, %Qubit* %qb) - br label %continue__1 - -else__1: ; preds = %entry - call void @__quantum__qis__single_qubit_op_ctl(i64 8, i64 1, %Array* %ctls, %Qubit* %qb) - br label %continue__1 - -continue__1: ; preds = %else__1, %then0__1 - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Z__ctladj(%Array* %__controlQubits__, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 1) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 1) - %0 = call i64 @__quantum__rt__array_get_size_1d(%Array* %__controlQubits__) - %1 = icmp eq i64 %0, 1 - br i1 %1, label %then0__1, label %else__1 - -then0__1: ; preds = %entry - call void @__quantum__qis__single_qubit_op_ctl(i64 7, i64 1, %Array* %__controlQubits__, %Qubit* %qb) - br label %continue__1 - -else__1: ; preds = %entry - call void @__quantum__qis__single_qubit_op_ctl(i64 8, i64 1, %Array* %__controlQubits__, %Qubit* %qb) - br label %continue__1 - -continue__1: ; preds = %else__1, %then0__1 - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 -1) - ret void -} - -define %Tuple* @Microsoft__Quantum__Core__Attribute__body() { -entry: - ret %Tuple* null -} - -define %Tuple* @Microsoft__Quantum__Core__EntryPoint__body() { -entry: - ret %Tuple* null -} - -define %Tuple* @Microsoft__Quantum__Core__Inline__body() { -entry: - ret %Tuple* null -} - -define %Result* @Microsoft__Quantum__Instructions__Mx__body(%Qubit* %qb) { -entry: - %0 = call %Result* @__quantum__qis__single_qubit_measure(i64 101, i64 1, %Qubit* %qb) - ret %Result* %0 -} - -define %Result* @Microsoft__Quantum__Instructions__Mxx__body(%Array* %qubits) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 1) - %0 = call %Result* @__quantum__qis__joint_measure(i64 105, i64 1, %Array* %qubits) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 -1) - ret %Result* %0 -} - -define %Result* @Microsoft__Quantum__Instructions__Mxz__body(%Array* %qubits) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 1) - %0 = call %Result* @__quantum__qis__joint_measure(i64 103, i64 1, %Array* %qubits) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 -1) - ret %Result* %0 -} - -define %Result* @Microsoft__Quantum__Instructions__Mz__body(%Qubit* %qb) { -entry: - %0 = call %Result* @__quantum__qis__single_qubit_measure(i64 100, i64 1, %Qubit* %qb) - ret %Result* %0 -} - -define %Result* @Microsoft__Quantum__Instructions__Mzx__body(%Array* %qubits) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 1) - %0 = call %Result* @__quantum__qis__joint_measure(i64 104, i64 1, %Array* %qubits) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 -1) - ret %Result* %0 -} - -define %Result* @Microsoft__Quantum__Instructions__Mzz__body(%Array* %qubits) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 1) - %0 = call %Result* @__quantum__qis__joint_measure(i64 102, i64 1, %Array* %qubits) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 -1) - ret %Result* %0 -} - -define void @Microsoft__Quantum__Instructions__Sx__body(%Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 17, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Instructions__Sx__adj(%Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 17, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Instructions__Sx__ctl(%Array* %ctls, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - call void @__quantum__qis__single_qubit_op_ctl(i64 18, i64 1, %Array* %ctls, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Instructions__Sx__ctladj(%Array* %ctls, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - call void @__quantum__qis__single_qubit_op_ctl(i64 18, i64 1, %Array* %ctls, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Instructions__Sz__body(%Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 15, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Instructions__Sz__adj(%Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 15, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Instructions__Sz__ctl(%Array* %ctls, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - call void @__quantum__qis__single_qubit_op_ctl(i64 16, i64 1, %Array* %ctls, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Instructions__Sz__ctladj(%Array* %ctls, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - call void @__quantum__qis__single_qubit_op_ctl(i64 16, i64 1, %Array* %ctls, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Instructions__Tx__body(%Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 13, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Instructions__Tx__adj(%Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 13, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Instructions__Tx__ctl(%Array* %ctls, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - call void @__quantum__qis__single_qubit_op_ctl(i64 14, i64 1, %Array* %ctls, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Instructions__Tx__ctladj(%Array* %ctls, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - call void @__quantum__qis__single_qubit_op_ctl(i64 14, i64 1, %Array* %ctls, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Instructions__Tz__body(%Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 11, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Instructions__Tz__adj(%Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 11, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Instructions__Tz__ctl(%Array* %ctls, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - call void @__quantum__qis__single_qubit_op_ctl(i64 12, i64 1, %Array* %ctls, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Instructions__Tz__ctladj(%Array* %ctls, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - call void @__quantum__qis__single_qubit_op_ctl(i64 12, i64 1, %Array* %ctls, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Testing__Tracer__Delay__body(%Callable* %op, %Qubit* %arg, %Tuple* %aux) { -entry: - call void @__quantum__rt__callable_memory_management(i32 1, %Callable* %op, i64 1) - call void @__quantum__rt__callable_update_alias_count(%Callable* %op, i64 1) - %0 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64)) - %1 = bitcast %Tuple* %0 to { %Qubit* }* - %2 = getelementptr inbounds { %Qubit* }, { %Qubit* }* %1, i32 0, i32 0 - store %Qubit* %arg, %Qubit** %2 - call void @__quantum__rt__callable_invoke(%Callable* %op, %Tuple* %0, %Tuple* null) - call void @__quantum__rt__callable_memory_management(i32 1, %Callable* %op, i64 -1) - call void @__quantum__rt__callable_update_alias_count(%Callable* %op, i64 -1) - call void @__quantum__rt__tuple_update_reference_count(%Tuple* %0, i64 -1) - ret void -} - -declare void @__quantum__rt__callable_invoke(%Callable*, %Tuple*, %Tuple*) - -define void @Microsoft__Quantum__Testing__Tracer__TestCoreIntrinsics__body() { -entry: - %qs = call %Array* @__quantum__rt__qubit_allocate_array(i64 3) - call void @__quantum__rt__array_update_alias_count(%Array* %qs, i64 1) - %0 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 0) - %1 = bitcast i8* %0 to %Qubit** - %qb = load %Qubit*, %Qubit** %1 - call void @__quantum__qis__single_qubit_op(i64 0, i64 1, %Qubit* %qb) - %2 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 0) - %3 = bitcast i8* %2 to %Qubit** - %qb__1 = load %Qubit*, %Qubit** %3 - call void @__quantum__qis__single_qubit_op(i64 3, i64 1, %Qubit* %qb__1) - %4 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 1) - %5 = bitcast i8* %4 to %Qubit** - %qb__2 = load %Qubit*, %Qubit** %5 - call void @__quantum__qis__single_qubit_op(i64 6, i64 1, %Qubit* %qb__2) - %6 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 1) - %7 = bitcast i8* %6 to %Qubit** - %qb__3 = load %Qubit*, %Qubit** %7 - call void @__quantum__qis__single_qubit_op(i64 9, i64 1, %Qubit* %qb__3) - %8 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 1) - %9 = bitcast i8* %8 to %Qubit** - %10 = load %Qubit*, %Qubit** %9 - %11 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 2) - %12 = bitcast i8* %11 to %Qubit** - %13 = load %Qubit*, %Qubit** %12 - call void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %10, %Qubit* %13) - %14 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 0) - %15 = bitcast i8* %14 to %Qubit** - %qb__4 = load %Qubit*, %Qubit** %15 - call void @__quantum__qis__single_qubit_op(i64 19, i64 1, %Qubit* %qb__4) - %16 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 1) - %17 = bitcast i8* %16 to %Qubit** - %qb__5 = load %Qubit*, %Qubit** %17 - call void @__quantum__qis__single_qubit_op(i64 21, i64 1, %Qubit* %qb__5) - %18 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 2) - %19 = bitcast i8* %18 to %Qubit** - %qb__6 = load %Qubit*, %Qubit** %19 - call void @__quantum__qis__single_qubit_op(i64 23, i64 1, %Qubit* %qb__6) - %20 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 1) - %21 = bitcast i8* %20 to %Qubit** - %qb__7 = load %Qubit*, %Qubit** %21 - call void @__quantum__qis__single_qubit_op(i64 15, i64 1, %Qubit* %qb__7) - %22 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 2) - %23 = bitcast i8* %22 to %Qubit** - %qb__9 = load %Qubit*, %Qubit** %23 - call void @__quantum__qis__single_qubit_op(i64 11, i64 1, %Qubit* %qb__9) - call void @__quantum__qis__inject_barrier(i64 42, i64 0) - %24 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 0) - %25 = bitcast i8* %24 to %Qubit** - %qb__11 = load %Qubit*, %Qubit** %25 - call void @__quantum__qis__single_qubit_op(i64 0, i64 1, %Qubit* %qb__11) - %26 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 0) - %27 = bitcast i8* %26 to %Qubit** - %qb__13 = load %Qubit*, %Qubit** %27 - call void @__quantum__qis__single_qubit_op(i64 3, i64 1, %Qubit* %qb__13) - %28 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 1) - %29 = bitcast i8* %28 to %Qubit** - %qb__15 = load %Qubit*, %Qubit** %29 - call void @__quantum__qis__single_qubit_op(i64 6, i64 1, %Qubit* %qb__15) - %30 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 1) - %31 = bitcast i8* %30 to %Qubit** - %qb__17 = load %Qubit*, %Qubit** %31 - call void @__quantum__qis__single_qubit_op(i64 9, i64 1, %Qubit* %qb__17) - %32 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 1) - %33 = bitcast i8* %32 to %Qubit** - %34 = load %Qubit*, %Qubit** %33 - %35 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 2) - %36 = bitcast i8* %35 to %Qubit** - %37 = load %Qubit*, %Qubit** %36 - call void @Microsoft__Quantum__Intrinsic__CNOT__adj(%Qubit* %34, %Qubit* %37) - %38 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 0) - %39 = bitcast i8* %38 to %Qubit** - %qb__19 = load %Qubit*, %Qubit** %39 - call void @__quantum__qis__single_qubit_op(i64 19, i64 1, %Qubit* %qb__19) - %40 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 1) - %41 = bitcast i8* %40 to %Qubit** - %qb__20 = load %Qubit*, %Qubit** %41 - call void @__quantum__qis__single_qubit_op(i64 21, i64 1, %Qubit* %qb__20) - %42 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 2) - %43 = bitcast i8* %42 to %Qubit** - %qb__21 = load %Qubit*, %Qubit** %43 - call void @__quantum__qis__single_qubit_op(i64 23, i64 1, %Qubit* %qb__21) - %44 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 1) - %45 = bitcast i8* %44 to %Qubit** - %qb__22 = load %Qubit*, %Qubit** %45 - call void @__quantum__qis__single_qubit_op(i64 15, i64 1, %Qubit* %qb__22) - %46 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 2) - %47 = bitcast i8* %46 to %Qubit** - %qb__24 = load %Qubit*, %Qubit** %47 - call void @__quantum__qis__single_qubit_op(i64 11, i64 1, %Qubit* %qb__24) - %c = call %Qubit* @__quantum__rt__qubit_allocate() - %ctls = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) - %48 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 0) - %49 = bitcast i8* %48 to %Qubit** - store %Qubit* %c, %Qubit** %49 - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - %50 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 0) - %51 = bitcast i8* %50 to %Qubit** - %qb__26 = load %Qubit*, %Qubit** %51 - br i1 true, label %then0__1, label %else__1 - -then0__1: ; preds = %entry - call void @__quantum__qis__single_qubit_op_ctl(i64 1, i64 1, %Array* %ctls, %Qubit* %qb__26) - br label %continue__1 - -else__1: ; preds = %entry - call void @__quantum__qis__single_qubit_op_ctl(i64 2, i64 1, %Array* %ctls, %Qubit* %qb__26) - br label %continue__1 - -continue__1: ; preds = %else__1, %then0__1 - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i64 -1) - %ctls__1 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) - %52 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls__1, i64 0) - %53 = bitcast i8* %52 to %Qubit** - store %Qubit* %c, %Qubit** %53 - call void @__quantum__rt__array_update_alias_count(%Array* %ctls__1, i64 1) - %54 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 0) - %55 = bitcast i8* %54 to %Qubit** - %qb__27 = load %Qubit*, %Qubit** %55 - br i1 true, label %then0__2, label %else__2 - -then0__2: ; preds = %continue__1 - call void @__quantum__qis__single_qubit_op_ctl(i64 4, i64 1, %Array* %ctls__1, %Qubit* %qb__27) - br label %continue__2 - -else__2: ; preds = %continue__1 - call void @__quantum__qis__single_qubit_op_ctl(i64 5, i64 1, %Array* %ctls__1, %Qubit* %qb__27) - br label %continue__2 - -continue__2: ; preds = %else__2, %then0__2 - call void @__quantum__rt__array_update_alias_count(%Array* %ctls__1, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %ctls__1, i64 -1) - %ctls__2 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) - %56 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls__2, i64 0) - %57 = bitcast i8* %56 to %Qubit** - store %Qubit* %c, %Qubit** %57 - call void @__quantum__rt__array_update_alias_count(%Array* %ctls__2, i64 1) - %58 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 1) - %59 = bitcast i8* %58 to %Qubit** - %qb__28 = load %Qubit*, %Qubit** %59 - br i1 true, label %then0__3, label %else__3 - -then0__3: ; preds = %continue__2 - call void @__quantum__qis__single_qubit_op_ctl(i64 7, i64 1, %Array* %ctls__2, %Qubit* %qb__28) - br label %continue__3 - -else__3: ; preds = %continue__2 - call void @__quantum__qis__single_qubit_op_ctl(i64 8, i64 1, %Array* %ctls__2, %Qubit* %qb__28) - br label %continue__3 - -continue__3: ; preds = %else__3, %then0__3 - call void @__quantum__rt__array_update_alias_count(%Array* %ctls__2, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %ctls__2, i64 -1) - %ctls__3 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) - %60 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls__3, i64 0) - %61 = bitcast i8* %60 to %Qubit** - store %Qubit* %c, %Qubit** %61 - call void @__quantum__rt__array_update_alias_count(%Array* %ctls__3, i64 1) - %62 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 1) - %63 = bitcast i8* %62 to %Qubit** - %qb__29 = load %Qubit*, %Qubit** %63 - call void @__quantum__qis__single_qubit_op_ctl(i64 10, i64 1, %Array* %ctls__3, %Qubit* %qb__29) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls__3, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %ctls__3, i64 -1) - %ctls__4 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) - %64 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls__4, i64 0) - %65 = bitcast i8* %64 to %Qubit** - store %Qubit* %c, %Qubit** %65 - call void @__quantum__rt__array_update_alias_count(%Array* %ctls__4, i64 1) - %66 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 0) - %67 = bitcast i8* %66 to %Qubit** - %qb__30 = load %Qubit*, %Qubit** %67 - call void @__quantum__qis__single_qubit_op_ctl(i64 20, i64 1, %Array* %ctls__4, %Qubit* %qb__30) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls__4, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %ctls__4, i64 -1) - %ctls__5 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) - %68 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls__5, i64 0) - %69 = bitcast i8* %68 to %Qubit** - store %Qubit* %c, %Qubit** %69 - call void @__quantum__rt__array_update_alias_count(%Array* %ctls__5, i64 1) - %70 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 1) - %71 = bitcast i8* %70 to %Qubit** - %qb__31 = load %Qubit*, %Qubit** %71 - call void @__quantum__qis__single_qubit_op_ctl(i64 22, i64 1, %Array* %ctls__5, %Qubit* %qb__31) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls__5, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %ctls__5, i64 -1) - %ctls__6 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) - %72 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls__6, i64 0) - %73 = bitcast i8* %72 to %Qubit** - store %Qubit* %c, %Qubit** %73 - call void @__quantum__rt__array_update_alias_count(%Array* %ctls__6, i64 1) - %74 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 2) - %75 = bitcast i8* %74 to %Qubit** - %qb__32 = load %Qubit*, %Qubit** %75 - call void @__quantum__qis__single_qubit_op_ctl(i64 24, i64 1, %Array* %ctls__6, %Qubit* %qb__32) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls__6, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %ctls__6, i64 -1) - %ctls__7 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) - %76 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls__7, i64 0) - %77 = bitcast i8* %76 to %Qubit** - store %Qubit* %c, %Qubit** %77 - call void @__quantum__rt__array_update_alias_count(%Array* %ctls__7, i64 1) - %78 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 1) - %79 = bitcast i8* %78 to %Qubit** - %qb__33 = load %Qubit*, %Qubit** %79 - call void @__quantum__rt__array_update_alias_count(%Array* %ctls__7, i64 1) - call void @__quantum__qis__single_qubit_op_ctl(i64 16, i64 1, %Array* %ctls__7, %Qubit* %qb__33) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls__7, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls__7, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %ctls__7, i64 -1) - %ctls__9 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) - %80 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls__9, i64 0) - %81 = bitcast i8* %80 to %Qubit** - store %Qubit* %c, %Qubit** %81 - call void @__quantum__rt__array_update_alias_count(%Array* %ctls__9, i64 1) - %82 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 2) - %83 = bitcast i8* %82 to %Qubit** - %qb__35 = load %Qubit*, %Qubit** %83 - call void @__quantum__rt__array_update_alias_count(%Array* %ctls__9, i64 1) - call void @__quantum__qis__single_qubit_op_ctl(i64 12, i64 1, %Array* %ctls__9, %Qubit* %qb__35) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls__9, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls__9, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %ctls__9, i64 -1) - call void @__quantum__rt__qubit_release(%Qubit* %c) - %cc = call %Array* @__quantum__rt__qubit_allocate_array(i64 2) - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 1) - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 1) - %84 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 0) - %85 = bitcast i8* %84 to %Qubit** - %qb__37 = load %Qubit*, %Qubit** %85 - %86 = call i64 @__quantum__rt__array_get_size_1d(%Array* %cc) - %87 = icmp eq i64 %86, 1 - br i1 %87, label %then0__4, label %else__4 - -then0__4: ; preds = %continue__3 - call void @__quantum__qis__single_qubit_op_ctl(i64 1, i64 1, %Array* %cc, %Qubit* %qb__37) - br label %continue__4 - -else__4: ; preds = %continue__3 - call void @__quantum__qis__single_qubit_op_ctl(i64 2, i64 1, %Array* %cc, %Qubit* %qb__37) - br label %continue__4 - -continue__4: ; preds = %else__4, %then0__4 - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 1) - %88 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 0) - %89 = bitcast i8* %88 to %Qubit** - %qb__38 = load %Qubit*, %Qubit** %89 - %90 = icmp eq i64 %86, 1 - br i1 %90, label %then0__5, label %else__5 - -then0__5: ; preds = %continue__4 - call void @__quantum__qis__single_qubit_op_ctl(i64 4, i64 1, %Array* %cc, %Qubit* %qb__38) - br label %continue__5 - -else__5: ; preds = %continue__4 - call void @__quantum__qis__single_qubit_op_ctl(i64 5, i64 1, %Array* %cc, %Qubit* %qb__38) - br label %continue__5 - -continue__5: ; preds = %else__5, %then0__5 - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 1) - %91 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 1) - %92 = bitcast i8* %91 to %Qubit** - %qb__39 = load %Qubit*, %Qubit** %92 - %93 = icmp eq i64 %86, 1 - br i1 %93, label %then0__6, label %else__6 - -then0__6: ; preds = %continue__5 - call void @__quantum__qis__single_qubit_op_ctl(i64 7, i64 1, %Array* %cc, %Qubit* %qb__39) - br label %continue__6 - -else__6: ; preds = %continue__5 - call void @__quantum__qis__single_qubit_op_ctl(i64 8, i64 1, %Array* %cc, %Qubit* %qb__39) - br label %continue__6 - -continue__6: ; preds = %else__6, %then0__6 - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 1) - %94 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 1) - %95 = bitcast i8* %94 to %Qubit** - %qb__40 = load %Qubit*, %Qubit** %95 - call void @__quantum__qis__single_qubit_op_ctl(i64 10, i64 1, %Array* %cc, %Qubit* %qb__40) - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 1) - %96 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 0) - %97 = bitcast i8* %96 to %Qubit** - %qb__41 = load %Qubit*, %Qubit** %97 - call void @__quantum__qis__single_qubit_op_ctl(i64 20, i64 1, %Array* %cc, %Qubit* %qb__41) - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 1) - %98 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 1) - %99 = bitcast i8* %98 to %Qubit** - %qb__42 = load %Qubit*, %Qubit** %99 - call void @__quantum__qis__single_qubit_op_ctl(i64 22, i64 1, %Array* %cc, %Qubit* %qb__42) - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 1) - %100 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 2) - %101 = bitcast i8* %100 to %Qubit** - %qb__43 = load %Qubit*, %Qubit** %101 - call void @__quantum__qis__single_qubit_op_ctl(i64 24, i64 1, %Array* %cc, %Qubit* %qb__43) - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 1) - %102 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 1) - %103 = bitcast i8* %102 to %Qubit** - %qb__44 = load %Qubit*, %Qubit** %103 - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 1) - call void @__quantum__qis__single_qubit_op_ctl(i64 16, i64 1, %Array* %cc, %Qubit* %qb__44) - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 1) - %104 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 2) - %105 = bitcast i8* %104 to %Qubit** - %qb__46 = load %Qubit*, %Qubit** %105 - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 1) - call void @__quantum__qis__single_qubit_op_ctl(i64 12, i64 1, %Array* %cc, %Qubit* %qb__46) - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 -1) - call void @__quantum__rt__qubit_release_array(%Array* %cc) - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %cc, i64 -1) - call void @__quantum__rt__qubit_release_array(%Array* %qs) - call void @__quantum__rt__array_update_alias_count(%Array* %qs, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %qs, i64 -1) - ret void -} - -declare %Qubit* @__quantum__rt__qubit_allocate() - -declare %Array* @__quantum__rt__qubit_allocate_array(i64) - -declare void @__quantum__qis__inject_barrier(i64, i64) - -declare void @__quantum__rt__qubit_release(%Qubit*) - -declare void @__quantum__rt__qubit_release_array(%Array*) - -define void @Microsoft__Quantum__Testing__Tracer__TestMeasurements__body() { -entry: - %qs = call %Array* @__quantum__rt__qubit_allocate_array(i64 6) - call void @__quantum__rt__array_update_alias_count(%Array* %qs, i64 1) - %0 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 0) - %1 = bitcast i8* %0 to %Qubit** - %qb = load %Qubit*, %Qubit** %1 - call void @__quantum__qis__single_qubit_op(i64 11, i64 1, %Qubit* %qb) - %2 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 0) - %3 = bitcast i8* %2 to %Qubit** - %qb__2 = load %Qubit*, %Qubit** %3 - %r0 = call %Result* @__quantum__qis__single_qubit_measure(i64 100, i64 1, %Qubit* %qb__2) - %4 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 1) - %5 = bitcast i8* %4 to %Qubit** - %qb__4 = load %Qubit*, %Qubit** %5 - call void @__quantum__qis__single_qubit_op(i64 11, i64 1, %Qubit* %qb__4) - %6 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 1) - %7 = bitcast i8* %6 to %Qubit** - %8 = load %Qubit*, %Qubit** %7 - %9 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 2) - %10 = bitcast i8* %9 to %Qubit** - %11 = load %Qubit*, %Qubit** %10 - call void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %8, %Qubit* %11) - %qs12 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 2) - %12 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs12, i64 0) - %13 = bitcast i8* %12 to %Qubit** - %14 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs12, i64 1) - %15 = bitcast i8* %14 to %Qubit** - %16 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 1) - %17 = bitcast i8* %16 to %Qubit** - %18 = load %Qubit*, %Qubit** %17 - %19 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 2) - %20 = bitcast i8* %19 to %Qubit** - %21 = load %Qubit*, %Qubit** %20 - store %Qubit* %18, %Qubit** %13 - store %Qubit* %21, %Qubit** %15 - call void @__quantum__rt__array_update_alias_count(%Array* %qs12, i64 1) - %paulis = call %Array* @__quantum__rt__array_create_1d(i32 1, i64 2) - %22 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 0) - %23 = bitcast i8* %22 to i2* - %24 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 1) - %25 = bitcast i8* %24 to i2* - %26 = load i2, i2* @PauliY - %27 = load i2, i2* @PauliX - store i2 %26, i2* %23 - store i2 %27, i2* %25 - call void @__quantum__rt__array_update_alias_count(%Array* %paulis, i64 1) - call void @__quantum__rt__array_update_alias_count(%Array* %qs12, i64 1) - %28 = load %Result*, %Result** @ResultOne - %res = alloca %Result* - store %Result* %28, %Result** %res - call void @__quantum__rt__result_update_reference_count(%Result* %28, i64 1) - %haveY = alloca i1 - store i1 false, i1* %haveY - br label %header__1 - -header__1: ; preds = %exiting__1, %entry - %i = phi i64 [ 0, %entry ], [ %41, %exiting__1 ] - %29 = icmp sle i64 %i, 1 - br i1 %29, label %body__1, label %exit__1 - -body__1: ; preds = %header__1 - %30 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 %i) - %31 = bitcast i8* %30 to i2* - %32 = load i2, i2* %31 - %33 = load i2, i2* @PauliY - %34 = icmp eq i2 %32, %33 - %35 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 %i) - %36 = bitcast i8* %35 to i2* - %37 = load i2, i2* %36 - %38 = load i2, i2* @PauliI - %39 = icmp eq i2 %37, %38 - %40 = or i1 %34, %39 - br i1 %40, label %then0__1, label %continue__1 - -then0__1: ; preds = %body__1 - store i1 true, i1* %haveY - br label %continue__1 - -continue__1: ; preds = %then0__1, %body__1 - br label %exiting__1 - -exiting__1: ; preds = %continue__1 - %41 = add i64 %i, 1 - br label %header__1 - -exit__1: ; preds = %header__1 - %42 = load i1, i1* %haveY - br i1 %42, label %then0__2, label %test1__1 - -then0__2: ; preds = %exit__1 - %43 = call %Result* @__quantum__qis__joint_measure(i64 106, i64 1, %Array* %qs12) - call void @__quantum__rt__result_update_reference_count(%Result* %43, i64 1) - store %Result* %43, %Result** %res - call void @__quantum__rt__result_update_reference_count(%Result* %43, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %28, i64 -1) - br label %continue__2 - -test1__1: ; preds = %exit__1 - br i1 false, label %then1__1, label %test2__1 - -then1__1: ; preds = %test1__1 - %44 = call %Result* @__quantum__qis__joint_measure(i64 107, i64 1, %Array* %qs12) - call void @__quantum__rt__result_update_reference_count(%Result* %44, i64 1) - %45 = load %Result*, %Result** %res - store %Result* %44, %Result** %res - call void @__quantum__rt__result_update_reference_count(%Result* %44, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %45, i64 -1) - br label %continue__2 - -test2__1: ; preds = %test1__1 - br i1 false, label %then2__1, label %test3__1 - -then2__1: ; preds = %test2__1 - %46 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 0) - %47 = bitcast i8* %46 to i2* - %48 = load i2, i2* %47 - %49 = load i2, i2* @PauliX - %50 = icmp eq i2 %48, %49 - br i1 %50, label %then0__3, label %else__1 - -then0__3: ; preds = %then2__1 - %51 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs12, i64 0) - %52 = bitcast i8* %51 to %Qubit** - %qb__6 = load %Qubit*, %Qubit** %52 - %53 = call %Result* @__quantum__qis__single_qubit_measure(i64 101, i64 1, %Qubit* %qb__6) - call void @__quantum__rt__result_update_reference_count(%Result* %53, i64 1) - %54 = load %Result*, %Result** %res - store %Result* %53, %Result** %res - call void @__quantum__rt__result_update_reference_count(%Result* %53, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %54, i64 -1) - br label %continue__3 - -else__1: ; preds = %then2__1 - %55 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs12, i64 0) - %56 = bitcast i8* %55 to %Qubit** - %qb__7 = load %Qubit*, %Qubit** %56 - %57 = call %Result* @__quantum__qis__single_qubit_measure(i64 100, i64 1, %Qubit* %qb__7) - call void @__quantum__rt__result_update_reference_count(%Result* %57, i64 1) - %58 = load %Result*, %Result** %res - store %Result* %57, %Result** %res - call void @__quantum__rt__result_update_reference_count(%Result* %57, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %58, i64 -1) - br label %continue__3 - -continue__3: ; preds = %else__1, %then0__3 - br label %continue__2 - -test3__1: ; preds = %test2__1 - %59 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 0) - %60 = bitcast i8* %59 to i2* - %61 = load i2, i2* %60 - %62 = load i2, i2* @PauliX - %63 = icmp eq i2 %61, %62 - %64 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 1) - %65 = bitcast i8* %64 to i2* - %66 = load i2, i2* %65 - %67 = load i2, i2* @PauliX - %68 = icmp eq i2 %66, %67 - %69 = and i1 %63, %68 - br i1 %69, label %then3__1, label %test4__1 - -then3__1: ; preds = %test3__1 - call void @__quantum__rt__array_update_alias_count(%Array* %qs12, i64 1) - %70 = call %Result* @__quantum__qis__joint_measure(i64 105, i64 1, %Array* %qs12) - call void @__quantum__rt__array_update_alias_count(%Array* %qs12, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %70, i64 1) - %71 = load %Result*, %Result** %res - store %Result* %70, %Result** %res - call void @__quantum__rt__result_update_reference_count(%Result* %70, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %71, i64 -1) - br label %continue__2 - -test4__1: ; preds = %test3__1 - %72 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 0) - %73 = bitcast i8* %72 to i2* - %74 = load i2, i2* %73 - %75 = load i2, i2* @PauliX - %76 = icmp eq i2 %74, %75 - %77 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 1) - %78 = bitcast i8* %77 to i2* - %79 = load i2, i2* %78 - %80 = load i2, i2* @PauliZ - %81 = icmp eq i2 %79, %80 - %82 = and i1 %76, %81 - br i1 %82, label %then4__1, label %test5__1 - -then4__1: ; preds = %test4__1 - call void @__quantum__rt__array_update_alias_count(%Array* %qs12, i64 1) - %83 = call %Result* @__quantum__qis__joint_measure(i64 103, i64 1, %Array* %qs12) - call void @__quantum__rt__array_update_alias_count(%Array* %qs12, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %83, i64 1) - %84 = load %Result*, %Result** %res - store %Result* %83, %Result** %res - call void @__quantum__rt__result_update_reference_count(%Result* %83, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %84, i64 -1) - br label %continue__2 - -test5__1: ; preds = %test4__1 - %85 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 0) - %86 = bitcast i8* %85 to i2* - %87 = load i2, i2* %86 - %88 = load i2, i2* @PauliZ - %89 = icmp eq i2 %87, %88 - %90 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 1) - %91 = bitcast i8* %90 to i2* - %92 = load i2, i2* %91 - %93 = load i2, i2* @PauliX - %94 = icmp eq i2 %92, %93 - %95 = and i1 %89, %94 - br i1 %95, label %then5__1, label %test6__1 - -then5__1: ; preds = %test5__1 - call void @__quantum__rt__array_update_alias_count(%Array* %qs12, i64 1) - %96 = call %Result* @__quantum__qis__joint_measure(i64 104, i64 1, %Array* %qs12) - call void @__quantum__rt__array_update_alias_count(%Array* %qs12, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %96, i64 1) - %97 = load %Result*, %Result** %res - store %Result* %96, %Result** %res - call void @__quantum__rt__result_update_reference_count(%Result* %96, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %97, i64 -1) - br label %continue__2 - -test6__1: ; preds = %test5__1 - %98 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 0) - %99 = bitcast i8* %98 to i2* - %100 = load i2, i2* %99 - %101 = load i2, i2* @PauliZ - %102 = icmp eq i2 %100, %101 - %103 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 1) - %104 = bitcast i8* %103 to i2* - %105 = load i2, i2* %104 - %106 = load i2, i2* @PauliZ - %107 = icmp eq i2 %105, %106 - %108 = and i1 %102, %107 - br i1 %108, label %then6__1, label %continue__2 - -then6__1: ; preds = %test6__1 - call void @__quantum__rt__array_update_alias_count(%Array* %qs12, i64 1) - %109 = call %Result* @__quantum__qis__joint_measure(i64 102, i64 1, %Array* %qs12) - call void @__quantum__rt__array_update_alias_count(%Array* %qs12, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %109, i64 1) - %110 = load %Result*, %Result** %res - store %Result* %109, %Result** %res - call void @__quantum__rt__result_update_reference_count(%Result* %109, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %110, i64 -1) - br label %continue__2 - -continue__2: ; preds = %then6__1, %test6__1, %then5__1, %then4__1, %then3__1, %continue__3, %then1__1, %then0__2 - %r12 = load %Result*, %Result** %res - call void @__quantum__rt__array_update_alias_count(%Array* %paulis, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %qs12, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %paulis, i64 -1) - %111 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 3)) - %112 = bitcast %Tuple* %111 to { %Callable*, %Callable*, %Qubit* }* - %113 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %112, i32 0, i32 0 - %114 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %112, i32 0, i32 1 - %115 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %112, i32 0, i32 2 - %116 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Testing__Tracer__Delay, [2 x void (%Tuple*, i64)*]* null, %Tuple* null) - %117 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__X, [2 x void (%Tuple*, i64)*]* null, %Tuple* null) - %118 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 3) - %119 = bitcast i8* %118 to %Qubit** - %120 = load %Qubit*, %Qubit** %119 - store %Callable* %116, %Callable** %113 - store %Callable* %117, %Callable** %114 - store %Qubit* %120, %Qubit** %115 - %121 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @PartialApplication__1, [2 x void (%Tuple*, i64)*]* @MemoryManagement__1, %Tuple* %111) - %122 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 3)) - %123 = bitcast %Tuple* %122 to { %Callable*, %Callable*, %Qubit* }* - %124 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %123, i32 0, i32 0 - %125 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %123, i32 0, i32 1 - %126 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %123, i32 0, i32 2 - %127 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Testing__Tracer__Delay, [2 x void (%Tuple*, i64)*]* null, %Tuple* null) - %128 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__Y, [2 x void (%Tuple*, i64)*]* null, %Tuple* null) - %129 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 3) - %130 = bitcast i8* %129 to %Qubit** - %131 = load %Qubit*, %Qubit** %130 - store %Callable* %127, %Callable** %124 - store %Callable* %128, %Callable** %125 - store %Qubit* %131, %Qubit** %126 - %132 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @PartialApplication__2, [2 x void (%Tuple*, i64)*]* @MemoryManagement__1, %Tuple* %122) - call void @Microsoft__Quantum__Intrinsic__ApplyIfElseIntrinsic__body(%Result* %r0, %Callable* %121, %Callable* %132) - %133 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 3)) - %134 = bitcast %Tuple* %133 to { %Callable*, %Callable*, %Qubit* }* - %135 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %134, i32 0, i32 0 - %136 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %134, i32 0, i32 1 - %137 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %134, i32 0, i32 2 - %138 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Testing__Tracer__Delay, [2 x void (%Tuple*, i64)*]* null, %Tuple* null) - %139 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__Z, [2 x void (%Tuple*, i64)*]* null, %Tuple* null) - %140 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 4) - %141 = bitcast i8* %140 to %Qubit** - %142 = load %Qubit*, %Qubit** %141 - store %Callable* %138, %Callable** %135 - store %Callable* %139, %Callable** %136 - store %Qubit* %142, %Qubit** %137 - %143 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @PartialApplication__3, [2 x void (%Tuple*, i64)*]* @MemoryManagement__1, %Tuple* %133) - %144 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 3)) - %145 = bitcast %Tuple* %144 to { %Callable*, %Callable*, %Qubit* }* - %146 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %145, i32 0, i32 0 - %147 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %145, i32 0, i32 1 - %148 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %145, i32 0, i32 2 - %149 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Testing__Tracer__Delay, [2 x void (%Tuple*, i64)*]* null, %Tuple* null) - %150 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__S, [2 x void (%Tuple*, i64)*]* null, %Tuple* null) - %151 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 4) - %152 = bitcast i8* %151 to %Qubit** - %153 = load %Qubit*, %Qubit** %152 - store %Callable* %149, %Callable** %146 - store %Callable* %150, %Callable** %147 - store %Qubit* %153, %Qubit** %148 - %154 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @PartialApplication__4, [2 x void (%Tuple*, i64)*]* @MemoryManagement__2, %Tuple* %144) - call void @Microsoft__Quantum__Intrinsic__ApplyIfElseIntrinsic__body(%Result* %r12, %Callable* %143, %Callable* %154) - %155 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 5) - %156 = bitcast i8* %155 to %Qubit** - %qb__8 = load %Qubit*, %Qubit** %156 - call void @__quantum__qis__single_qubit_op(i64 19, i64 1, %Qubit* %qb__8) - call void @__quantum__rt__qubit_release_array(%Array* %qs) - call void @__quantum__rt__array_update_alias_count(%Array* %qs, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %qs12, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %qs, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %r0, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %qs12, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %r12, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %121, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %121, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %132, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %132, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %143, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %143, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %154, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %154, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Testing__Tracer__Delay__body__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Callable*, %Qubit*, %Tuple* }* - %1 = getelementptr inbounds { %Callable*, %Qubit*, %Tuple* }, { %Callable*, %Qubit*, %Tuple* }* %0, i32 0, i32 0 - %2 = getelementptr inbounds { %Callable*, %Qubit*, %Tuple* }, { %Callable*, %Qubit*, %Tuple* }* %0, i32 0, i32 1 - %3 = getelementptr inbounds { %Callable*, %Qubit*, %Tuple* }, { %Callable*, %Qubit*, %Tuple* }* %0, i32 0, i32 2 - %4 = load %Callable*, %Callable** %1 - %5 = load %Qubit*, %Qubit** %2 - %6 = load %Tuple*, %Tuple** %3 - call void @Microsoft__Quantum__Testing__Tracer__Delay__body(%Callable* %4, %Qubit* %5, %Tuple* %6) - ret void -} - -declare %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]*, [2 x void (%Tuple*, i64)*]*, %Tuple*) - -define void @Microsoft__Quantum__Intrinsic__X__body__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Qubit* }* - %1 = getelementptr inbounds { %Qubit* }, { %Qubit* }* %0, i32 0, i32 0 - %2 = load %Qubit*, %Qubit** %1 - call void @Microsoft__Quantum__Intrinsic__X__body(%Qubit* %2) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__X__adj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Qubit* }* - %1 = getelementptr inbounds { %Qubit* }, { %Qubit* }* %0, i32 0, i32 0 - %2 = load %Qubit*, %Qubit** %1 - call void @Microsoft__Quantum__Intrinsic__X__adj(%Qubit* %2) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__X__ctl__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Array*, %Qubit* }* - %1 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 0 - %2 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 1 - %3 = load %Array*, %Array** %1 - %4 = load %Qubit*, %Qubit** %2 - call void @Microsoft__Quantum__Intrinsic__X__ctl(%Array* %3, %Qubit* %4) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__X__ctladj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Array*, %Qubit* }* - %1 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 0 - %2 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 1 - %3 = load %Array*, %Array** %1 - %4 = load %Qubit*, %Qubit** %2 - call void @Microsoft__Quantum__Intrinsic__X__ctladj(%Array* %3, %Qubit* %4) - ret void -} - -define void @Lifted__PartialApplication__1__body__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %capture-tuple to { %Callable*, %Callable*, %Qubit* }* - %1 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %0, i32 0, i32 1 - %2 = load %Callable*, %Callable** %1 - %3 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %0, i32 0, i32 2 - %4 = load %Qubit*, %Qubit** %3 - %5 = bitcast %Tuple* %arg-tuple to { %Tuple* }* - %6 = getelementptr inbounds { %Tuple* }, { %Tuple* }* %5, i32 0, i32 0 - %7 = load %Tuple*, %Tuple** %6 - %8 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 3)) - %9 = bitcast %Tuple* %8 to { %Callable*, %Qubit*, %Tuple* }* - %10 = getelementptr inbounds { %Callable*, %Qubit*, %Tuple* }, { %Callable*, %Qubit*, %Tuple* }* %9, i32 0, i32 0 - %11 = getelementptr inbounds { %Callable*, %Qubit*, %Tuple* }, { %Callable*, %Qubit*, %Tuple* }* %9, i32 0, i32 1 - %12 = getelementptr inbounds { %Callable*, %Qubit*, %Tuple* }, { %Callable*, %Qubit*, %Tuple* }* %9, i32 0, i32 2 - store %Callable* %2, %Callable** %10 - store %Qubit* %4, %Qubit** %11 - store %Tuple* %7, %Tuple** %12 - %13 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %0, i32 0, i32 0 - %14 = load %Callable*, %Callable** %13 - call void @__quantum__rt__callable_invoke(%Callable* %14, %Tuple* %8, %Tuple* %result-tuple) - call void @__quantum__rt__tuple_update_reference_count(%Tuple* %8, i64 -1) - ret void -} - -define void @MemoryManagement__1__RefCount(%Tuple* %capture-tuple, i64 %count-change) { -entry: - %0 = bitcast %Tuple* %capture-tuple to { %Callable*, %Callable*, %Qubit* }* - %1 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %0, i32 0, i32 0 - %2 = load %Callable*, %Callable** %1 - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %2, i64 %count-change) - call void @__quantum__rt__callable_update_reference_count(%Callable* %2, i64 %count-change) - %3 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %0, i32 0, i32 1 - %4 = load %Callable*, %Callable** %3 - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %4, i64 %count-change) - call void @__quantum__rt__callable_update_reference_count(%Callable* %4, i64 %count-change) - call void @__quantum__rt__tuple_update_reference_count(%Tuple* %capture-tuple, i64 %count-change) - ret void -} - -define void @MemoryManagement__1__AliasCount(%Tuple* %capture-tuple, i64 %count-change) { -entry: - %0 = bitcast %Tuple* %capture-tuple to { %Callable*, %Callable*, %Qubit* }* - %1 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %0, i32 0, i32 0 - %2 = load %Callable*, %Callable** %1 - call void @__quantum__rt__callable_memory_management(i32 1, %Callable* %2, i64 %count-change) - call void @__quantum__rt__callable_update_alias_count(%Callable* %2, i64 %count-change) - %3 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %0, i32 0, i32 1 - %4 = load %Callable*, %Callable** %3 - call void @__quantum__rt__callable_memory_management(i32 1, %Callable* %4, i64 %count-change) - call void @__quantum__rt__callable_update_alias_count(%Callable* %4, i64 %count-change) - call void @__quantum__rt__tuple_update_alias_count(%Tuple* %capture-tuple, i64 %count-change) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Y__body__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Qubit* }* - %1 = getelementptr inbounds { %Qubit* }, { %Qubit* }* %0, i32 0, i32 0 - %2 = load %Qubit*, %Qubit** %1 - call void @Microsoft__Quantum__Intrinsic__Y__body(%Qubit* %2) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Y__adj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Qubit* }* - %1 = getelementptr inbounds { %Qubit* }, { %Qubit* }* %0, i32 0, i32 0 - %2 = load %Qubit*, %Qubit** %1 - call void @Microsoft__Quantum__Intrinsic__Y__adj(%Qubit* %2) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Y__ctl__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Array*, %Qubit* }* - %1 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 0 - %2 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 1 - %3 = load %Array*, %Array** %1 - %4 = load %Qubit*, %Qubit** %2 - call void @Microsoft__Quantum__Intrinsic__Y__ctl(%Array* %3, %Qubit* %4) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Y__ctladj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Array*, %Qubit* }* - %1 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 0 - %2 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 1 - %3 = load %Array*, %Array** %1 - %4 = load %Qubit*, %Qubit** %2 - call void @Microsoft__Quantum__Intrinsic__Y__ctladj(%Array* %3, %Qubit* %4) - ret void -} - -define void @Lifted__PartialApplication__2__body__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %capture-tuple to { %Callable*, %Callable*, %Qubit* }* - %1 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %0, i32 0, i32 1 - %2 = load %Callable*, %Callable** %1 - %3 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %0, i32 0, i32 2 - %4 = load %Qubit*, %Qubit** %3 - %5 = bitcast %Tuple* %arg-tuple to { %Tuple* }* - %6 = getelementptr inbounds { %Tuple* }, { %Tuple* }* %5, i32 0, i32 0 - %7 = load %Tuple*, %Tuple** %6 - %8 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 3)) - %9 = bitcast %Tuple* %8 to { %Callable*, %Qubit*, %Tuple* }* - %10 = getelementptr inbounds { %Callable*, %Qubit*, %Tuple* }, { %Callable*, %Qubit*, %Tuple* }* %9, i32 0, i32 0 - %11 = getelementptr inbounds { %Callable*, %Qubit*, %Tuple* }, { %Callable*, %Qubit*, %Tuple* }* %9, i32 0, i32 1 - %12 = getelementptr inbounds { %Callable*, %Qubit*, %Tuple* }, { %Callable*, %Qubit*, %Tuple* }* %9, i32 0, i32 2 - store %Callable* %2, %Callable** %10 - store %Qubit* %4, %Qubit** %11 - store %Tuple* %7, %Tuple** %12 - %13 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %0, i32 0, i32 0 - %14 = load %Callable*, %Callable** %13 - call void @__quantum__rt__callable_invoke(%Callable* %14, %Tuple* %8, %Tuple* %result-tuple) - call void @__quantum__rt__tuple_update_reference_count(%Tuple* %8, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Z__body__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Qubit* }* - %1 = getelementptr inbounds { %Qubit* }, { %Qubit* }* %0, i32 0, i32 0 - %2 = load %Qubit*, %Qubit** %1 - call void @Microsoft__Quantum__Intrinsic__Z__body(%Qubit* %2) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Z__adj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Qubit* }* - %1 = getelementptr inbounds { %Qubit* }, { %Qubit* }* %0, i32 0, i32 0 - %2 = load %Qubit*, %Qubit** %1 - call void @Microsoft__Quantum__Intrinsic__Z__adj(%Qubit* %2) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Z__ctl__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Array*, %Qubit* }* - %1 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 0 - %2 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 1 - %3 = load %Array*, %Array** %1 - %4 = load %Qubit*, %Qubit** %2 - call void @Microsoft__Quantum__Intrinsic__Z__ctl(%Array* %3, %Qubit* %4) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Z__ctladj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Array*, %Qubit* }* - %1 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 0 - %2 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 1 - %3 = load %Array*, %Array** %1 - %4 = load %Qubit*, %Qubit** %2 - call void @Microsoft__Quantum__Intrinsic__Z__ctladj(%Array* %3, %Qubit* %4) - ret void -} - -define void @Lifted__PartialApplication__3__body__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %capture-tuple to { %Callable*, %Callable*, %Qubit* }* - %1 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %0, i32 0, i32 1 - %2 = load %Callable*, %Callable** %1 - %3 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %0, i32 0, i32 2 - %4 = load %Qubit*, %Qubit** %3 - %5 = bitcast %Tuple* %arg-tuple to { %Tuple* }* - %6 = getelementptr inbounds { %Tuple* }, { %Tuple* }* %5, i32 0, i32 0 - %7 = load %Tuple*, %Tuple** %6 - %8 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 3)) - %9 = bitcast %Tuple* %8 to { %Callable*, %Qubit*, %Tuple* }* - %10 = getelementptr inbounds { %Callable*, %Qubit*, %Tuple* }, { %Callable*, %Qubit*, %Tuple* }* %9, i32 0, i32 0 - %11 = getelementptr inbounds { %Callable*, %Qubit*, %Tuple* }, { %Callable*, %Qubit*, %Tuple* }* %9, i32 0, i32 1 - %12 = getelementptr inbounds { %Callable*, %Qubit*, %Tuple* }, { %Callable*, %Qubit*, %Tuple* }* %9, i32 0, i32 2 - store %Callable* %2, %Callable** %10 - store %Qubit* %4, %Qubit** %11 - store %Tuple* %7, %Tuple** %12 - %13 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %0, i32 0, i32 0 - %14 = load %Callable*, %Callable** %13 - call void @__quantum__rt__callable_invoke(%Callable* %14, %Tuple* %8, %Tuple* %result-tuple) - call void @__quantum__rt__tuple_update_reference_count(%Tuple* %8, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__S__body__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Qubit* }* - %1 = getelementptr inbounds { %Qubit* }, { %Qubit* }* %0, i32 0, i32 0 - %2 = load %Qubit*, %Qubit** %1 - call void @Microsoft__Quantum__Intrinsic__S__body(%Qubit* %2) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__S__adj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Qubit* }* - %1 = getelementptr inbounds { %Qubit* }, { %Qubit* }* %0, i32 0, i32 0 - %2 = load %Qubit*, %Qubit** %1 - call void @Microsoft__Quantum__Intrinsic__S__adj(%Qubit* %2) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__S__ctl__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Array*, %Qubit* }* - %1 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 0 - %2 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 1 - %3 = load %Array*, %Array** %1 - %4 = load %Qubit*, %Qubit** %2 - call void @Microsoft__Quantum__Intrinsic__S__ctl(%Array* %3, %Qubit* %4) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__S__ctladj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Array*, %Qubit* }* - %1 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 0 - %2 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 1 - %3 = load %Array*, %Array** %1 - %4 = load %Qubit*, %Qubit** %2 - call void @Microsoft__Quantum__Intrinsic__S__ctladj(%Array* %3, %Qubit* %4) - ret void -} - -define void @Lifted__PartialApplication__4__body__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %capture-tuple to { %Callable*, %Callable*, %Qubit* }* - %1 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %0, i32 0, i32 1 - %2 = load %Callable*, %Callable** %1 - %3 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %0, i32 0, i32 2 - %4 = load %Qubit*, %Qubit** %3 - %5 = bitcast %Tuple* %arg-tuple to { %Tuple* }* - %6 = getelementptr inbounds { %Tuple* }, { %Tuple* }* %5, i32 0, i32 0 - %7 = load %Tuple*, %Tuple** %6 - %8 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 3)) - %9 = bitcast %Tuple* %8 to { %Callable*, %Qubit*, %Tuple* }* - %10 = getelementptr inbounds { %Callable*, %Qubit*, %Tuple* }, { %Callable*, %Qubit*, %Tuple* }* %9, i32 0, i32 0 - %11 = getelementptr inbounds { %Callable*, %Qubit*, %Tuple* }, { %Callable*, %Qubit*, %Tuple* }* %9, i32 0, i32 1 - %12 = getelementptr inbounds { %Callable*, %Qubit*, %Tuple* }, { %Callable*, %Qubit*, %Tuple* }* %9, i32 0, i32 2 - store %Callable* %2, %Callable** %10 - store %Qubit* %4, %Qubit** %11 - store %Tuple* %7, %Tuple** %12 - %13 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %0, i32 0, i32 0 - %14 = load %Callable*, %Callable** %13 - call void @__quantum__rt__callable_invoke(%Callable* %14, %Tuple* %8, %Tuple* %result-tuple) - call void @__quantum__rt__tuple_update_reference_count(%Tuple* %8, i64 -1) - ret void -} - -define void @MemoryManagement__2__RefCount(%Tuple* %capture-tuple, i64 %count-change) { -entry: - %0 = bitcast %Tuple* %capture-tuple to { %Callable*, %Callable*, %Qubit* }* - %1 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %0, i32 0, i32 0 - %2 = load %Callable*, %Callable** %1 - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %2, i64 %count-change) - call void @__quantum__rt__callable_update_reference_count(%Callable* %2, i64 %count-change) - %3 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %0, i32 0, i32 1 - %4 = load %Callable*, %Callable** %3 - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %4, i64 %count-change) - call void @__quantum__rt__callable_update_reference_count(%Callable* %4, i64 %count-change) - call void @__quantum__rt__tuple_update_reference_count(%Tuple* %capture-tuple, i64 %count-change) - ret void -} - -define void @MemoryManagement__2__AliasCount(%Tuple* %capture-tuple, i64 %count-change) { -entry: - %0 = bitcast %Tuple* %capture-tuple to { %Callable*, %Callable*, %Qubit* }* - %1 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %0, i32 0, i32 0 - %2 = load %Callable*, %Callable** %1 - call void @__quantum__rt__callable_memory_management(i32 1, %Callable* %2, i64 %count-change) - call void @__quantum__rt__callable_update_alias_count(%Callable* %2, i64 %count-change) - %3 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %0, i32 0, i32 1 - %4 = load %Callable*, %Callable** %3 - call void @__quantum__rt__callable_memory_management(i32 1, %Callable* %4, i64 %count-change) - call void @__quantum__rt__callable_update_alias_count(%Callable* %4, i64 %count-change) - call void @__quantum__rt__tuple_update_alias_count(%Tuple* %capture-tuple, i64 %count-change) - ret void -} - -declare void @__quantum__rt__callable_update_reference_count(%Callable*, i64) - -define { %String* }* @Microsoft__Quantum__Targeting__TargetInstruction__body(%String* %__Item1__) { -entry: - %0 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64)) - %1 = bitcast %Tuple* %0 to { %String* }* - %2 = getelementptr inbounds { %String* }, { %String* }* %1, i32 0, i32 0 - store %String* %__Item1__, %String** %2 - call void @__quantum__rt__string_update_reference_count(%String* %__Item1__, i64 1) - ret { %String* }* %1 -} - -declare void @__quantum__rt__string_update_reference_count(%String*, i64) - -declare void @__quantum__rt__tuple_update_alias_count(%Tuple*, i64) diff --git a/src/QirRuntime/test/QIR-tracer/tracer-qir-win.ll b/src/QirRuntime/test/QIR-tracer/tracer-qir-win.ll deleted file mode 100644 index c53abaa2d2e..00000000000 --- a/src/QirRuntime/test/QIR-tracer/tracer-qir-win.ll +++ /dev/null @@ -1,2019 +0,0 @@ - -%Result = type opaque -%Range = type { i64, i64, i64 } -%Tuple = type opaque -%Array = type opaque -%Callable = type opaque -%Qubit = type opaque -%String = type opaque - -@ResultZero = external dllimport global %Result* -@ResultOne = external dllimport global %Result* -@PauliI = constant i2 0 -@PauliX = constant i2 1 -@PauliY = constant i2 -1 -@PauliZ = constant i2 -2 -@EmptyRange = internal constant %Range { i64 0, i64 1, i64 -1 } -@Microsoft__Quantum__Testing__Tracer__Delay = constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Testing__Tracer__Delay__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* null, void (%Tuple*, %Tuple*, %Tuple*)* null, void (%Tuple*, %Tuple*, %Tuple*)* null] -@Microsoft__Quantum__Intrinsic__X = constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__X__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__X__adj__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__X__ctl__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__X__ctladj__wrapper] -@PartialApplication__1 = constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Lifted__PartialApplication__1__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* null, void (%Tuple*, %Tuple*, %Tuple*)* null, void (%Tuple*, %Tuple*, %Tuple*)* null] -@MemoryManagement__1 = constant [2 x void (%Tuple*, i64)*] [void (%Tuple*, i64)* @MemoryManagement__1__RefCount, void (%Tuple*, i64)* @MemoryManagement__1__AliasCount] -@Microsoft__Quantum__Intrinsic__Y = constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Y__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Y__adj__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Y__ctl__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Y__ctladj__wrapper] -@PartialApplication__2 = constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Lifted__PartialApplication__2__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* null, void (%Tuple*, %Tuple*, %Tuple*)* null, void (%Tuple*, %Tuple*, %Tuple*)* null] -@Microsoft__Quantum__Intrinsic__Z = constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Z__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Z__adj__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Z__ctl__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Z__ctladj__wrapper] -@PartialApplication__3 = constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Lifted__PartialApplication__3__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* null, void (%Tuple*, %Tuple*, %Tuple*)* null, void (%Tuple*, %Tuple*, %Tuple*)* null] -@Microsoft__Quantum__Intrinsic__S = constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__S__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__S__adj__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__S__ctl__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__S__ctladj__wrapper] -@PartialApplication__4 = constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Lifted__PartialApplication__4__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* null, void (%Tuple*, %Tuple*, %Tuple*)* null, void (%Tuple*, %Tuple*, %Tuple*)* null] -@MemoryManagement__2 = constant [2 x void (%Tuple*, i64)*] [void (%Tuple*, i64)* @MemoryManagement__2__RefCount, void (%Tuple*, i64)* @MemoryManagement__2__AliasCount] - -define void @Microsoft__Quantum__Intrinsic__ApplyConditionallyIntrinsic__body(%Array* %measurementResults, %Array* %resultsValues, %Callable* %onEqualOp, %Callable* %onNonEqualOp) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %measurementResults, i64 1) - call void @__quantum__rt__array_update_alias_count(%Array* %resultsValues, i64 1) - call void @__quantum__rt__callable_memory_management(i32 1, %Callable* %onEqualOp, i64 1) - call void @__quantum__rt__callable_update_alias_count(%Callable* %onEqualOp, i64 1) - call void @__quantum__rt__callable_memory_management(i32 1, %Callable* %onNonEqualOp, i64 1) - call void @__quantum__rt__callable_update_alias_count(%Callable* %onNonEqualOp, i64 1) - call void @__quantum__qis__apply_conditionally(%Array* %measurementResults, %Array* %resultsValues, %Callable* %onEqualOp, %Callable* %onNonEqualOp) - call void @__quantum__rt__array_update_alias_count(%Array* %measurementResults, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %resultsValues, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 1, %Callable* %onEqualOp, i64 -1) - call void @__quantum__rt__callable_update_alias_count(%Callable* %onEqualOp, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 1, %Callable* %onNonEqualOp, i64 -1) - call void @__quantum__rt__callable_update_alias_count(%Callable* %onNonEqualOp, i64 -1) - ret void -} - -declare void @__quantum__rt__array_update_alias_count(%Array*, i64) - -declare void @__quantum__rt__callable_memory_management(i32, %Callable*, i64) - -declare void @__quantum__rt__callable_update_alias_count(%Callable*, i64) - -declare void @__quantum__qis__apply_conditionally(%Array*, %Array*, %Callable*, %Callable*) - -define void @Microsoft__Quantum__Intrinsic__ApplyIfElseIntrinsic__body(%Result* %measurementResult, %Callable* %onResultZeroOp, %Callable* %onResultOneOp) { -entry: - call void @__quantum__rt__callable_memory_management(i32 1, %Callable* %onResultZeroOp, i64 1) - call void @__quantum__rt__callable_update_alias_count(%Callable* %onResultZeroOp, i64 1) - call void @__quantum__rt__callable_memory_management(i32 1, %Callable* %onResultOneOp, i64 1) - call void @__quantum__rt__callable_update_alias_count(%Callable* %onResultOneOp, i64 1) - %0 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) - %1 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %0, i64 0) - %2 = bitcast i8* %1 to %Result** - store %Result* %measurementResult, %Result** %2 - %3 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) - %4 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %3, i64 0) - %5 = bitcast i8* %4 to %Result** - %6 = load %Result*, %Result** @ResultZero - store %Result* %6, %Result** %5 - call void @__quantum__qis__apply_conditionally(%Array* %0, %Array* %3, %Callable* %onResultZeroOp, %Callable* %onResultOneOp) - call void @__quantum__rt__result_update_reference_count(%Result* %measurementResult, i64 1) - call void @__quantum__rt__result_update_reference_count(%Result* %6, i64 1) - call void @__quantum__rt__callable_memory_management(i32 1, %Callable* %onResultZeroOp, i64 -1) - call void @__quantum__rt__callable_update_alias_count(%Callable* %onResultZeroOp, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 1, %Callable* %onResultOneOp, i64 -1) - call void @__quantum__rt__callable_update_alias_count(%Callable* %onResultOneOp, i64 -1) - br label %header__1 - -header__1: ; preds = %exiting__1, %entry - %7 = phi i64 [ 0, %entry ], [ %12, %exiting__1 ] - %8 = icmp sle i64 %7, 0 - br i1 %8, label %body__1, label %exit__1 - -body__1: ; preds = %header__1 - %9 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %0, i64 %7) - %10 = bitcast i8* %9 to %Result** - %11 = load %Result*, %Result** %10 - call void @__quantum__rt__result_update_reference_count(%Result* %11, i64 -1) - br label %exiting__1 - -exiting__1: ; preds = %body__1 - %12 = add i64 %7, 1 - br label %header__1 - -exit__1: ; preds = %header__1 - call void @__quantum__rt__array_update_reference_count(%Array* %0, i64 -1) - br label %header__2 - -header__2: ; preds = %exiting__2, %exit__1 - %13 = phi i64 [ 0, %exit__1 ], [ %18, %exiting__2 ] - %14 = icmp sle i64 %13, 0 - br i1 %14, label %body__2, label %exit__2 - -body__2: ; preds = %header__2 - %15 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %3, i64 %13) - %16 = bitcast i8* %15 to %Result** - %17 = load %Result*, %Result** %16 - call void @__quantum__rt__result_update_reference_count(%Result* %17, i64 -1) - br label %exiting__2 - -exiting__2: ; preds = %body__2 - %18 = add i64 %13, 1 - br label %header__2 - -exit__2: ; preds = %header__2 - call void @__quantum__rt__array_update_reference_count(%Array* %3, i64 -1) - ret void -} - -declare %Array* @__quantum__rt__array_create_1d(i32, i64) - -declare i8* @__quantum__rt__array_get_element_ptr_1d(%Array*, i64) - -declare void @__quantum__rt__result_update_reference_count(%Result*, i64) - -declare void @__quantum__rt__array_update_reference_count(%Array*, i64) - -define void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %control, %Qubit* %target) { -entry: - %ctls = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) - %0 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 0) - %1 = bitcast i8* %0 to %Qubit** - store %Qubit* %control, %Qubit** %1 - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - br i1 true, label %then0__1, label %else__1 - -then0__1: ; preds = %entry - call void @__quantum__qis__single_qubit_op_ctl(i64 1, i64 1, %Array* %ctls, %Qubit* %target) - br label %continue__1 - -else__1: ; preds = %entry - call void @__quantum__qis__single_qubit_op_ctl(i64 2, i64 1, %Array* %ctls, %Qubit* %target) - br label %continue__1 - -continue__1: ; preds = %else__1, %then0__1 - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i64 -1) - ret void -} - -declare void @__quantum__qis__single_qubit_op_ctl(i64, i64, %Array*, %Qubit*) - -define void @Microsoft__Quantum__Intrinsic__CNOT__adj(%Qubit* %control, %Qubit* %target) { -entry: - call void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %control, %Qubit* %target) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__CNOT__ctl(%Array* %ctls, { %Qubit*, %Qubit* }* %0) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - %1 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %0, i32 0, i32 0 - %control = load %Qubit*, %Qubit** %1 - %2 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %0, i32 0, i32 1 - %target = load %Qubit*, %Qubit** %2 - %3 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) - %4 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %3, i64 0) - %5 = bitcast i8* %4 to %Qubit** - store %Qubit* %control, %Qubit** %5 - %ctls__1 = call %Array* @__quantum__rt__array_concatenate(%Array* %ctls, %Array* %3) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls__1, i64 1) - %6 = call i64 @__quantum__rt__array_get_size_1d(%Array* %ctls__1) - %7 = icmp eq i64 %6, 1 - br i1 %7, label %then0__1, label %else__1 - -then0__1: ; preds = %entry - call void @__quantum__qis__single_qubit_op_ctl(i64 1, i64 1, %Array* %ctls__1, %Qubit* %target) - br label %continue__1 - -else__1: ; preds = %entry - call void @__quantum__qis__single_qubit_op_ctl(i64 2, i64 1, %Array* %ctls__1, %Qubit* %target) - br label %continue__1 - -continue__1: ; preds = %else__1, %then0__1 - call void @__quantum__rt__array_update_alias_count(%Array* %ctls__1, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %3, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %ctls__1, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -declare %Array* @__quantum__rt__array_concatenate(%Array*, %Array*) - -declare i64 @__quantum__rt__array_get_size_1d(%Array*) - -define void @Microsoft__Quantum__Intrinsic__CNOT__ctladj(%Array* %__controlQubits__, { %Qubit*, %Qubit* }* %0) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 1) - %1 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %0, i32 0, i32 0 - %control = load %Qubit*, %Qubit** %1 - %2 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %0, i32 0, i32 1 - %target = load %Qubit*, %Qubit** %2 - %3 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) - %4 = bitcast %Tuple* %3 to { %Qubit*, %Qubit* }* - %5 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %4, i32 0, i32 0 - %6 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %4, i32 0, i32 1 - store %Qubit* %control, %Qubit** %5 - store %Qubit* %target, %Qubit** %6 - call void @Microsoft__Quantum__Intrinsic__CNOT__ctl(%Array* %__controlQubits__, { %Qubit*, %Qubit* }* %4) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 -1) - call void @__quantum__rt__tuple_update_reference_count(%Tuple* %3, i64 -1) - ret void -} - -declare %Tuple* @__quantum__rt__tuple_create(i64) - -declare void @__quantum__rt__tuple_update_reference_count(%Tuple*, i64) - -define void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 9, i64 1, %Qubit* %qb) - ret void -} - -declare void @__quantum__qis__single_qubit_op(i64, i64, %Qubit*) - -define void @Microsoft__Quantum__Intrinsic__H__adj(%Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 9, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__H__ctl(%Array* %ctls, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - call void @__quantum__qis__single_qubit_op_ctl(i64 10, i64 1, %Array* %ctls, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__H__ctladj(%Array* %__controlQubits__, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 1) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 1) - call void @__quantum__qis__single_qubit_op_ctl(i64 10, i64 1, %Array* %__controlQubits__, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 -1) - ret void -} - -define %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %qb) { -entry: - %0 = call %Result* @__quantum__qis__single_qubit_measure(i64 100, i64 1, %Qubit* %qb) - ret %Result* %0 -} - -declare %Result* @__quantum__qis__single_qubit_measure(i64, i64, %Qubit*) - -define %Result* @Microsoft__Quantum__Intrinsic__Measure__body(%Array* %paulis, %Array* %qubits) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %paulis, i64 1) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 1) - %0 = load %Result*, %Result** @ResultOne - %res = alloca %Result* - store %Result* %0, %Result** %res - call void @__quantum__rt__result_update_reference_count(%Result* %0, i64 1) - %haveY = alloca i1 - store i1 false, i1* %haveY - %1 = call i64 @__quantum__rt__array_get_size_1d(%Array* %paulis) - %2 = sub i64 %1, 1 - br label %header__1 - -header__1: ; preds = %exiting__1, %entry - %i = phi i64 [ 0, %entry ], [ %15, %exiting__1 ] - %3 = icmp sle i64 %i, %2 - br i1 %3, label %body__1, label %exit__1 - -body__1: ; preds = %header__1 - %4 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 %i) - %5 = bitcast i8* %4 to i2* - %6 = load i2, i2* %5 - %7 = load i2, i2* @PauliY - %8 = icmp eq i2 %6, %7 - %9 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 %i) - %10 = bitcast i8* %9 to i2* - %11 = load i2, i2* %10 - %12 = load i2, i2* @PauliI - %13 = icmp eq i2 %11, %12 - %14 = or i1 %8, %13 - br i1 %14, label %then0__1, label %continue__1 - -then0__1: ; preds = %body__1 - store i1 true, i1* %haveY - br label %continue__1 - -continue__1: ; preds = %then0__1, %body__1 - br label %exiting__1 - -exiting__1: ; preds = %continue__1 - %15 = add i64 %i, 1 - br label %header__1 - -exit__1: ; preds = %header__1 - %16 = load i1, i1* %haveY - br i1 %16, label %then0__2, label %test1__1 - -then0__2: ; preds = %exit__1 - %17 = call %Result* @__quantum__qis__joint_measure(i64 106, i64 1, %Array* %qubits) - call void @__quantum__rt__result_update_reference_count(%Result* %17, i64 1) - store %Result* %17, %Result** %res - call void @__quantum__rt__result_update_reference_count(%Result* %17, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %0, i64 -1) - br label %continue__2 - -test1__1: ; preds = %exit__1 - %18 = icmp sgt i64 %1, 2 - br i1 %18, label %then1__1, label %test2__1 - -then1__1: ; preds = %test1__1 - %19 = call %Result* @__quantum__qis__joint_measure(i64 107, i64 1, %Array* %qubits) - call void @__quantum__rt__result_update_reference_count(%Result* %19, i64 1) - %20 = load %Result*, %Result** %res - store %Result* %19, %Result** %res - call void @__quantum__rt__result_update_reference_count(%Result* %19, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %20, i64 -1) - br label %continue__2 - -test2__1: ; preds = %test1__1 - %21 = icmp eq i64 %1, 1 - br i1 %21, label %then2__1, label %test3__1 - -then2__1: ; preds = %test2__1 - %22 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 0) - %23 = bitcast i8* %22 to i2* - %24 = load i2, i2* %23 - %25 = load i2, i2* @PauliX - %26 = icmp eq i2 %24, %25 - br i1 %26, label %then0__3, label %else__1 - -then0__3: ; preds = %then2__1 - %27 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qubits, i64 0) - %28 = bitcast i8* %27 to %Qubit** - %qb = load %Qubit*, %Qubit** %28 - %29 = call %Result* @__quantum__qis__single_qubit_measure(i64 101, i64 1, %Qubit* %qb) - call void @__quantum__rt__result_update_reference_count(%Result* %29, i64 1) - %30 = load %Result*, %Result** %res - store %Result* %29, %Result** %res - call void @__quantum__rt__result_update_reference_count(%Result* %29, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %30, i64 -1) - br label %continue__3 - -else__1: ; preds = %then2__1 - %31 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qubits, i64 0) - %32 = bitcast i8* %31 to %Qubit** - %qb__1 = load %Qubit*, %Qubit** %32 - %33 = call %Result* @__quantum__qis__single_qubit_measure(i64 100, i64 1, %Qubit* %qb__1) - call void @__quantum__rt__result_update_reference_count(%Result* %33, i64 1) - %34 = load %Result*, %Result** %res - store %Result* %33, %Result** %res - call void @__quantum__rt__result_update_reference_count(%Result* %33, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %34, i64 -1) - br label %continue__3 - -continue__3: ; preds = %else__1, %then0__3 - br label %continue__2 - -test3__1: ; preds = %test2__1 - %35 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 0) - %36 = bitcast i8* %35 to i2* - %37 = load i2, i2* %36 - %38 = load i2, i2* @PauliX - %39 = icmp eq i2 %37, %38 - %40 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 1) - %41 = bitcast i8* %40 to i2* - %42 = load i2, i2* %41 - %43 = load i2, i2* @PauliX - %44 = icmp eq i2 %42, %43 - %45 = and i1 %39, %44 - br i1 %45, label %then3__1, label %test4__1 - -then3__1: ; preds = %test3__1 - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 1) - %46 = call %Result* @__quantum__qis__joint_measure(i64 105, i64 1, %Array* %qubits) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %46, i64 1) - %47 = load %Result*, %Result** %res - store %Result* %46, %Result** %res - call void @__quantum__rt__result_update_reference_count(%Result* %46, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %47, i64 -1) - br label %continue__2 - -test4__1: ; preds = %test3__1 - %48 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 0) - %49 = bitcast i8* %48 to i2* - %50 = load i2, i2* %49 - %51 = load i2, i2* @PauliX - %52 = icmp eq i2 %50, %51 - %53 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 1) - %54 = bitcast i8* %53 to i2* - %55 = load i2, i2* %54 - %56 = load i2, i2* @PauliZ - %57 = icmp eq i2 %55, %56 - %58 = and i1 %52, %57 - br i1 %58, label %then4__1, label %test5__1 - -then4__1: ; preds = %test4__1 - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 1) - %59 = call %Result* @__quantum__qis__joint_measure(i64 103, i64 1, %Array* %qubits) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %59, i64 1) - %60 = load %Result*, %Result** %res - store %Result* %59, %Result** %res - call void @__quantum__rt__result_update_reference_count(%Result* %59, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %60, i64 -1) - br label %continue__2 - -test5__1: ; preds = %test4__1 - %61 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 0) - %62 = bitcast i8* %61 to i2* - %63 = load i2, i2* %62 - %64 = load i2, i2* @PauliZ - %65 = icmp eq i2 %63, %64 - %66 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 1) - %67 = bitcast i8* %66 to i2* - %68 = load i2, i2* %67 - %69 = load i2, i2* @PauliX - %70 = icmp eq i2 %68, %69 - %71 = and i1 %65, %70 - br i1 %71, label %then5__1, label %test6__1 - -then5__1: ; preds = %test5__1 - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 1) - %72 = call %Result* @__quantum__qis__joint_measure(i64 104, i64 1, %Array* %qubits) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %72, i64 1) - %73 = load %Result*, %Result** %res - store %Result* %72, %Result** %res - call void @__quantum__rt__result_update_reference_count(%Result* %72, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %73, i64 -1) - br label %continue__2 - -test6__1: ; preds = %test5__1 - %74 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 0) - %75 = bitcast i8* %74 to i2* - %76 = load i2, i2* %75 - %77 = load i2, i2* @PauliZ - %78 = icmp eq i2 %76, %77 - %79 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 1) - %80 = bitcast i8* %79 to i2* - %81 = load i2, i2* %80 - %82 = load i2, i2* @PauliZ - %83 = icmp eq i2 %81, %82 - %84 = and i1 %78, %83 - br i1 %84, label %then6__1, label %continue__2 - -then6__1: ; preds = %test6__1 - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 1) - %85 = call %Result* @__quantum__qis__joint_measure(i64 102, i64 1, %Array* %qubits) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %85, i64 1) - %86 = load %Result*, %Result** %res - store %Result* %85, %Result** %res - call void @__quantum__rt__result_update_reference_count(%Result* %85, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %86, i64 -1) - br label %continue__2 - -continue__2: ; preds = %then6__1, %test6__1, %then5__1, %then4__1, %then3__1, %continue__3, %then1__1, %then0__2 - %87 = load %Result*, %Result** %res - call void @__quantum__rt__array_update_alias_count(%Array* %paulis, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 -1) - ret %Result* %87 -} - -declare %Result* @__quantum__qis__joint_measure(i64, i64, %Array*) - -define void @Microsoft__Quantum__Intrinsic__Rx__body(double %theta, %Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 19, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Rx__adj(double %theta, %Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 19, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Rx__ctl(%Array* %ctls, { double, %Qubit* }* %0) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - %1 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 0 - %theta = load double, double* %1 - %2 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 1 - %qb = load %Qubit*, %Qubit** %2 - call void @__quantum__qis__single_qubit_op_ctl(i64 20, i64 1, %Array* %ctls, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Rx__ctladj(%Array* %ctls, { double, %Qubit* }* %0) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - %1 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 0 - %theta = load double, double* %1 - %2 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 1 - %qb = load %Qubit*, %Qubit** %2 - call void @__quantum__qis__single_qubit_op_ctl(i64 20, i64 1, %Array* %ctls, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Ry__body(double %theta, %Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 21, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Ry__adj(double %theta, %Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 21, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Ry__ctl(%Array* %ctls, { double, %Qubit* }* %0) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - %1 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 0 - %theta = load double, double* %1 - %2 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 1 - %qb = load %Qubit*, %Qubit** %2 - call void @__quantum__qis__single_qubit_op_ctl(i64 22, i64 1, %Array* %ctls, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Ry__ctladj(%Array* %ctls, { double, %Qubit* }* %0) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - %1 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 0 - %theta = load double, double* %1 - %2 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 1 - %qb = load %Qubit*, %Qubit** %2 - call void @__quantum__qis__single_qubit_op_ctl(i64 22, i64 1, %Array* %ctls, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Rz__body(double %theta, %Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 23, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Rz__adj(double %theta, %Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 23, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Rz__ctl(%Array* %ctls, { double, %Qubit* }* %0) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - %1 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 0 - %theta = load double, double* %1 - %2 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 1 - %qb = load %Qubit*, %Qubit** %2 - call void @__quantum__qis__single_qubit_op_ctl(i64 24, i64 1, %Array* %ctls, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Rz__ctladj(%Array* %ctls, { double, %Qubit* }* %0) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - %1 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 0 - %theta = load double, double* %1 - %2 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 1 - %qb = load %Qubit*, %Qubit** %2 - call void @__quantum__qis__single_qubit_op_ctl(i64 24, i64 1, %Array* %ctls, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__S__body(%Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 15, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__S__adj(%Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 15, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__S__ctl(%Array* %ctls, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - call void @__quantum__qis__single_qubit_op_ctl(i64 16, i64 1, %Array* %ctls, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__S__ctladj(%Array* %ctls, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - call void @__quantum__qis__single_qubit_op_ctl(i64 16, i64 1, %Array* %ctls, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__T__body(%Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 11, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__T__adj(%Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 11, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__T__ctl(%Array* %ctls, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - call void @__quantum__qis__single_qubit_op_ctl(i64 12, i64 1, %Array* %ctls, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__T__ctladj(%Array* %ctls, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - call void @__quantum__qis__single_qubit_op_ctl(i64 12, i64 1, %Array* %ctls, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__X__body(%Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 0, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__X__adj(%Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 0, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__X__ctl(%Array* %ctls, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - %0 = call i64 @__quantum__rt__array_get_size_1d(%Array* %ctls) - %1 = icmp eq i64 %0, 1 - br i1 %1, label %then0__1, label %else__1 - -then0__1: ; preds = %entry - call void @__quantum__qis__single_qubit_op_ctl(i64 1, i64 1, %Array* %ctls, %Qubit* %qb) - br label %continue__1 - -else__1: ; preds = %entry - call void @__quantum__qis__single_qubit_op_ctl(i64 2, i64 1, %Array* %ctls, %Qubit* %qb) - br label %continue__1 - -continue__1: ; preds = %else__1, %then0__1 - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__X__ctladj(%Array* %__controlQubits__, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 1) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 1) - %0 = call i64 @__quantum__rt__array_get_size_1d(%Array* %__controlQubits__) - %1 = icmp eq i64 %0, 1 - br i1 %1, label %then0__1, label %else__1 - -then0__1: ; preds = %entry - call void @__quantum__qis__single_qubit_op_ctl(i64 1, i64 1, %Array* %__controlQubits__, %Qubit* %qb) - br label %continue__1 - -else__1: ; preds = %entry - call void @__quantum__qis__single_qubit_op_ctl(i64 2, i64 1, %Array* %__controlQubits__, %Qubit* %qb) - br label %continue__1 - -continue__1: ; preds = %else__1, %then0__1 - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Y__body(%Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 3, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Y__adj(%Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 3, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Y__ctl(%Array* %ctls, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - %0 = call i64 @__quantum__rt__array_get_size_1d(%Array* %ctls) - %1 = icmp eq i64 %0, 1 - br i1 %1, label %then0__1, label %else__1 - -then0__1: ; preds = %entry - call void @__quantum__qis__single_qubit_op_ctl(i64 4, i64 1, %Array* %ctls, %Qubit* %qb) - br label %continue__1 - -else__1: ; preds = %entry - call void @__quantum__qis__single_qubit_op_ctl(i64 5, i64 1, %Array* %ctls, %Qubit* %qb) - br label %continue__1 - -continue__1: ; preds = %else__1, %then0__1 - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Y__ctladj(%Array* %__controlQubits__, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 1) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 1) - %0 = call i64 @__quantum__rt__array_get_size_1d(%Array* %__controlQubits__) - %1 = icmp eq i64 %0, 1 - br i1 %1, label %then0__1, label %else__1 - -then0__1: ; preds = %entry - call void @__quantum__qis__single_qubit_op_ctl(i64 4, i64 1, %Array* %__controlQubits__, %Qubit* %qb) - br label %continue__1 - -else__1: ; preds = %entry - call void @__quantum__qis__single_qubit_op_ctl(i64 5, i64 1, %Array* %__controlQubits__, %Qubit* %qb) - br label %continue__1 - -continue__1: ; preds = %else__1, %then0__1 - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Z__body(%Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 6, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Z__adj(%Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 6, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Z__ctl(%Array* %ctls, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - %0 = call i64 @__quantum__rt__array_get_size_1d(%Array* %ctls) - %1 = icmp eq i64 %0, 1 - br i1 %1, label %then0__1, label %else__1 - -then0__1: ; preds = %entry - call void @__quantum__qis__single_qubit_op_ctl(i64 7, i64 1, %Array* %ctls, %Qubit* %qb) - br label %continue__1 - -else__1: ; preds = %entry - call void @__quantum__qis__single_qubit_op_ctl(i64 8, i64 1, %Array* %ctls, %Qubit* %qb) - br label %continue__1 - -continue__1: ; preds = %else__1, %then0__1 - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Z__ctladj(%Array* %__controlQubits__, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 1) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 1) - %0 = call i64 @__quantum__rt__array_get_size_1d(%Array* %__controlQubits__) - %1 = icmp eq i64 %0, 1 - br i1 %1, label %then0__1, label %else__1 - -then0__1: ; preds = %entry - call void @__quantum__qis__single_qubit_op_ctl(i64 7, i64 1, %Array* %__controlQubits__, %Qubit* %qb) - br label %continue__1 - -else__1: ; preds = %entry - call void @__quantum__qis__single_qubit_op_ctl(i64 8, i64 1, %Array* %__controlQubits__, %Qubit* %qb) - br label %continue__1 - -continue__1: ; preds = %else__1, %then0__1 - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i64 -1) - ret void -} - -define %Tuple* @Microsoft__Quantum__Core__Attribute__body() { -entry: - ret %Tuple* null -} - -define %Tuple* @Microsoft__Quantum__Core__EntryPoint__body() { -entry: - ret %Tuple* null -} - -define %Tuple* @Microsoft__Quantum__Core__Inline__body() { -entry: - ret %Tuple* null -} - -define %Result* @Microsoft__Quantum__Instructions__Mx__body(%Qubit* %qb) { -entry: - %0 = call %Result* @__quantum__qis__single_qubit_measure(i64 101, i64 1, %Qubit* %qb) - ret %Result* %0 -} - -define %Result* @Microsoft__Quantum__Instructions__Mxx__body(%Array* %qubits) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 1) - %0 = call %Result* @__quantum__qis__joint_measure(i64 105, i64 1, %Array* %qubits) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 -1) - ret %Result* %0 -} - -define %Result* @Microsoft__Quantum__Instructions__Mxz__body(%Array* %qubits) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 1) - %0 = call %Result* @__quantum__qis__joint_measure(i64 103, i64 1, %Array* %qubits) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 -1) - ret %Result* %0 -} - -define %Result* @Microsoft__Quantum__Instructions__Mz__body(%Qubit* %qb) { -entry: - %0 = call %Result* @__quantum__qis__single_qubit_measure(i64 100, i64 1, %Qubit* %qb) - ret %Result* %0 -} - -define %Result* @Microsoft__Quantum__Instructions__Mzx__body(%Array* %qubits) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 1) - %0 = call %Result* @__quantum__qis__joint_measure(i64 104, i64 1, %Array* %qubits) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 -1) - ret %Result* %0 -} - -define %Result* @Microsoft__Quantum__Instructions__Mzz__body(%Array* %qubits) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 1) - %0 = call %Result* @__quantum__qis__joint_measure(i64 102, i64 1, %Array* %qubits) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i64 -1) - ret %Result* %0 -} - -define void @Microsoft__Quantum__Instructions__Sx__body(%Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 17, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Instructions__Sx__adj(%Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 17, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Instructions__Sx__ctl(%Array* %ctls, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - call void @__quantum__qis__single_qubit_op_ctl(i64 18, i64 1, %Array* %ctls, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Instructions__Sx__ctladj(%Array* %ctls, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - call void @__quantum__qis__single_qubit_op_ctl(i64 18, i64 1, %Array* %ctls, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Instructions__Sz__body(%Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 15, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Instructions__Sz__adj(%Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 15, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Instructions__Sz__ctl(%Array* %ctls, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - call void @__quantum__qis__single_qubit_op_ctl(i64 16, i64 1, %Array* %ctls, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Instructions__Sz__ctladj(%Array* %ctls, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - call void @__quantum__qis__single_qubit_op_ctl(i64 16, i64 1, %Array* %ctls, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Instructions__Tx__body(%Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 13, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Instructions__Tx__adj(%Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 13, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Instructions__Tx__ctl(%Array* %ctls, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - call void @__quantum__qis__single_qubit_op_ctl(i64 14, i64 1, %Array* %ctls, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Instructions__Tx__ctladj(%Array* %ctls, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - call void @__quantum__qis__single_qubit_op_ctl(i64 14, i64 1, %Array* %ctls, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Instructions__Tz__body(%Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 11, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Instructions__Tz__adj(%Qubit* %qb) { -entry: - call void @__quantum__qis__single_qubit_op(i64 11, i64 1, %Qubit* %qb) - ret void -} - -define void @Microsoft__Quantum__Instructions__Tz__ctl(%Array* %ctls, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - call void @__quantum__qis__single_qubit_op_ctl(i64 12, i64 1, %Array* %ctls, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Instructions__Tz__ctladj(%Array* %ctls, %Qubit* %qb) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - call void @__quantum__qis__single_qubit_op_ctl(i64 12, i64 1, %Array* %ctls, %Qubit* %qb) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Testing__Tracer__Delay__body(%Callable* %op, %Qubit* %arg, %Tuple* %aux) { -entry: - call void @__quantum__rt__callable_memory_management(i32 1, %Callable* %op, i64 1) - call void @__quantum__rt__callable_update_alias_count(%Callable* %op, i64 1) - %0 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64)) - %1 = bitcast %Tuple* %0 to { %Qubit* }* - %2 = getelementptr inbounds { %Qubit* }, { %Qubit* }* %1, i32 0, i32 0 - store %Qubit* %arg, %Qubit** %2 - call void @__quantum__rt__callable_invoke(%Callable* %op, %Tuple* %0, %Tuple* null) - call void @__quantum__rt__callable_memory_management(i32 1, %Callable* %op, i64 -1) - call void @__quantum__rt__callable_update_alias_count(%Callable* %op, i64 -1) - call void @__quantum__rt__tuple_update_reference_count(%Tuple* %0, i64 -1) - ret void -} - -declare void @__quantum__rt__callable_invoke(%Callable*, %Tuple*, %Tuple*) - -define void @Microsoft__Quantum__Testing__Tracer__TestCoreIntrinsics__body() { -entry: - %qs = call %Array* @__quantum__rt__qubit_allocate_array(i64 3) - call void @__quantum__rt__array_update_alias_count(%Array* %qs, i64 1) - %0 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 0) - %1 = bitcast i8* %0 to %Qubit** - %qb = load %Qubit*, %Qubit** %1 - call void @__quantum__qis__single_qubit_op(i64 0, i64 1, %Qubit* %qb) - %2 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 0) - %3 = bitcast i8* %2 to %Qubit** - %qb__1 = load %Qubit*, %Qubit** %3 - call void @__quantum__qis__single_qubit_op(i64 3, i64 1, %Qubit* %qb__1) - %4 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 1) - %5 = bitcast i8* %4 to %Qubit** - %qb__2 = load %Qubit*, %Qubit** %5 - call void @__quantum__qis__single_qubit_op(i64 6, i64 1, %Qubit* %qb__2) - %6 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 1) - %7 = bitcast i8* %6 to %Qubit** - %qb__3 = load %Qubit*, %Qubit** %7 - call void @__quantum__qis__single_qubit_op(i64 9, i64 1, %Qubit* %qb__3) - %8 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 1) - %9 = bitcast i8* %8 to %Qubit** - %10 = load %Qubit*, %Qubit** %9 - %11 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 2) - %12 = bitcast i8* %11 to %Qubit** - %13 = load %Qubit*, %Qubit** %12 - call void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %10, %Qubit* %13) - %14 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 0) - %15 = bitcast i8* %14 to %Qubit** - %qb__4 = load %Qubit*, %Qubit** %15 - call void @__quantum__qis__single_qubit_op(i64 19, i64 1, %Qubit* %qb__4) - %16 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 1) - %17 = bitcast i8* %16 to %Qubit** - %qb__5 = load %Qubit*, %Qubit** %17 - call void @__quantum__qis__single_qubit_op(i64 21, i64 1, %Qubit* %qb__5) - %18 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 2) - %19 = bitcast i8* %18 to %Qubit** - %qb__6 = load %Qubit*, %Qubit** %19 - call void @__quantum__qis__single_qubit_op(i64 23, i64 1, %Qubit* %qb__6) - %20 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 1) - %21 = bitcast i8* %20 to %Qubit** - %qb__7 = load %Qubit*, %Qubit** %21 - call void @__quantum__qis__single_qubit_op(i64 15, i64 1, %Qubit* %qb__7) - %22 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 2) - %23 = bitcast i8* %22 to %Qubit** - %qb__9 = load %Qubit*, %Qubit** %23 - call void @__quantum__qis__single_qubit_op(i64 11, i64 1, %Qubit* %qb__9) - call void @__quantum__qis__inject_barrier(i64 42, i64 0) - %24 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 0) - %25 = bitcast i8* %24 to %Qubit** - %qb__11 = load %Qubit*, %Qubit** %25 - call void @__quantum__qis__single_qubit_op(i64 0, i64 1, %Qubit* %qb__11) - %26 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 0) - %27 = bitcast i8* %26 to %Qubit** - %qb__13 = load %Qubit*, %Qubit** %27 - call void @__quantum__qis__single_qubit_op(i64 3, i64 1, %Qubit* %qb__13) - %28 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 1) - %29 = bitcast i8* %28 to %Qubit** - %qb__15 = load %Qubit*, %Qubit** %29 - call void @__quantum__qis__single_qubit_op(i64 6, i64 1, %Qubit* %qb__15) - %30 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 1) - %31 = bitcast i8* %30 to %Qubit** - %qb__17 = load %Qubit*, %Qubit** %31 - call void @__quantum__qis__single_qubit_op(i64 9, i64 1, %Qubit* %qb__17) - %32 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 1) - %33 = bitcast i8* %32 to %Qubit** - %34 = load %Qubit*, %Qubit** %33 - %35 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 2) - %36 = bitcast i8* %35 to %Qubit** - %37 = load %Qubit*, %Qubit** %36 - call void @Microsoft__Quantum__Intrinsic__CNOT__adj(%Qubit* %34, %Qubit* %37) - %38 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 0) - %39 = bitcast i8* %38 to %Qubit** - %qb__19 = load %Qubit*, %Qubit** %39 - call void @__quantum__qis__single_qubit_op(i64 19, i64 1, %Qubit* %qb__19) - %40 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 1) - %41 = bitcast i8* %40 to %Qubit** - %qb__20 = load %Qubit*, %Qubit** %41 - call void @__quantum__qis__single_qubit_op(i64 21, i64 1, %Qubit* %qb__20) - %42 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 2) - %43 = bitcast i8* %42 to %Qubit** - %qb__21 = load %Qubit*, %Qubit** %43 - call void @__quantum__qis__single_qubit_op(i64 23, i64 1, %Qubit* %qb__21) - %44 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 1) - %45 = bitcast i8* %44 to %Qubit** - %qb__22 = load %Qubit*, %Qubit** %45 - call void @__quantum__qis__single_qubit_op(i64 15, i64 1, %Qubit* %qb__22) - %46 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 2) - %47 = bitcast i8* %46 to %Qubit** - %qb__24 = load %Qubit*, %Qubit** %47 - call void @__quantum__qis__single_qubit_op(i64 11, i64 1, %Qubit* %qb__24) - %c = call %Qubit* @__quantum__rt__qubit_allocate() - %ctls = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) - %48 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 0) - %49 = bitcast i8* %48 to %Qubit** - store %Qubit* %c, %Qubit** %49 - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 1) - %50 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 0) - %51 = bitcast i8* %50 to %Qubit** - %qb__26 = load %Qubit*, %Qubit** %51 - br i1 true, label %then0__1, label %else__1 - -then0__1: ; preds = %entry - call void @__quantum__qis__single_qubit_op_ctl(i64 1, i64 1, %Array* %ctls, %Qubit* %qb__26) - br label %continue__1 - -else__1: ; preds = %entry - call void @__quantum__qis__single_qubit_op_ctl(i64 2, i64 1, %Array* %ctls, %Qubit* %qb__26) - br label %continue__1 - -continue__1: ; preds = %else__1, %then0__1 - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i64 -1) - %ctls__1 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) - %52 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls__1, i64 0) - %53 = bitcast i8* %52 to %Qubit** - store %Qubit* %c, %Qubit** %53 - call void @__quantum__rt__array_update_alias_count(%Array* %ctls__1, i64 1) - %54 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 0) - %55 = bitcast i8* %54 to %Qubit** - %qb__27 = load %Qubit*, %Qubit** %55 - br i1 true, label %then0__2, label %else__2 - -then0__2: ; preds = %continue__1 - call void @__quantum__qis__single_qubit_op_ctl(i64 4, i64 1, %Array* %ctls__1, %Qubit* %qb__27) - br label %continue__2 - -else__2: ; preds = %continue__1 - call void @__quantum__qis__single_qubit_op_ctl(i64 5, i64 1, %Array* %ctls__1, %Qubit* %qb__27) - br label %continue__2 - -continue__2: ; preds = %else__2, %then0__2 - call void @__quantum__rt__array_update_alias_count(%Array* %ctls__1, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %ctls__1, i64 -1) - %ctls__2 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) - %56 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls__2, i64 0) - %57 = bitcast i8* %56 to %Qubit** - store %Qubit* %c, %Qubit** %57 - call void @__quantum__rt__array_update_alias_count(%Array* %ctls__2, i64 1) - %58 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 1) - %59 = bitcast i8* %58 to %Qubit** - %qb__28 = load %Qubit*, %Qubit** %59 - br i1 true, label %then0__3, label %else__3 - -then0__3: ; preds = %continue__2 - call void @__quantum__qis__single_qubit_op_ctl(i64 7, i64 1, %Array* %ctls__2, %Qubit* %qb__28) - br label %continue__3 - -else__3: ; preds = %continue__2 - call void @__quantum__qis__single_qubit_op_ctl(i64 8, i64 1, %Array* %ctls__2, %Qubit* %qb__28) - br label %continue__3 - -continue__3: ; preds = %else__3, %then0__3 - call void @__quantum__rt__array_update_alias_count(%Array* %ctls__2, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %ctls__2, i64 -1) - %ctls__3 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) - %60 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls__3, i64 0) - %61 = bitcast i8* %60 to %Qubit** - store %Qubit* %c, %Qubit** %61 - call void @__quantum__rt__array_update_alias_count(%Array* %ctls__3, i64 1) - %62 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 1) - %63 = bitcast i8* %62 to %Qubit** - %qb__29 = load %Qubit*, %Qubit** %63 - call void @__quantum__qis__single_qubit_op_ctl(i64 10, i64 1, %Array* %ctls__3, %Qubit* %qb__29) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls__3, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %ctls__3, i64 -1) - %ctls__4 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) - %64 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls__4, i64 0) - %65 = bitcast i8* %64 to %Qubit** - store %Qubit* %c, %Qubit** %65 - call void @__quantum__rt__array_update_alias_count(%Array* %ctls__4, i64 1) - %66 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 0) - %67 = bitcast i8* %66 to %Qubit** - %qb__30 = load %Qubit*, %Qubit** %67 - call void @__quantum__qis__single_qubit_op_ctl(i64 20, i64 1, %Array* %ctls__4, %Qubit* %qb__30) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls__4, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %ctls__4, i64 -1) - %ctls__5 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) - %68 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls__5, i64 0) - %69 = bitcast i8* %68 to %Qubit** - store %Qubit* %c, %Qubit** %69 - call void @__quantum__rt__array_update_alias_count(%Array* %ctls__5, i64 1) - %70 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 1) - %71 = bitcast i8* %70 to %Qubit** - %qb__31 = load %Qubit*, %Qubit** %71 - call void @__quantum__qis__single_qubit_op_ctl(i64 22, i64 1, %Array* %ctls__5, %Qubit* %qb__31) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls__5, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %ctls__5, i64 -1) - %ctls__6 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) - %72 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls__6, i64 0) - %73 = bitcast i8* %72 to %Qubit** - store %Qubit* %c, %Qubit** %73 - call void @__quantum__rt__array_update_alias_count(%Array* %ctls__6, i64 1) - %74 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 2) - %75 = bitcast i8* %74 to %Qubit** - %qb__32 = load %Qubit*, %Qubit** %75 - call void @__quantum__qis__single_qubit_op_ctl(i64 24, i64 1, %Array* %ctls__6, %Qubit* %qb__32) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls__6, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %ctls__6, i64 -1) - %ctls__7 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) - %76 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls__7, i64 0) - %77 = bitcast i8* %76 to %Qubit** - store %Qubit* %c, %Qubit** %77 - call void @__quantum__rt__array_update_alias_count(%Array* %ctls__7, i64 1) - %78 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 1) - %79 = bitcast i8* %78 to %Qubit** - %qb__33 = load %Qubit*, %Qubit** %79 - call void @__quantum__rt__array_update_alias_count(%Array* %ctls__7, i64 1) - call void @__quantum__qis__single_qubit_op_ctl(i64 16, i64 1, %Array* %ctls__7, %Qubit* %qb__33) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls__7, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls__7, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %ctls__7, i64 -1) - %ctls__9 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) - %80 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls__9, i64 0) - %81 = bitcast i8* %80 to %Qubit** - store %Qubit* %c, %Qubit** %81 - call void @__quantum__rt__array_update_alias_count(%Array* %ctls__9, i64 1) - %82 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 2) - %83 = bitcast i8* %82 to %Qubit** - %qb__35 = load %Qubit*, %Qubit** %83 - call void @__quantum__rt__array_update_alias_count(%Array* %ctls__9, i64 1) - call void @__quantum__qis__single_qubit_op_ctl(i64 12, i64 1, %Array* %ctls__9, %Qubit* %qb__35) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls__9, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %ctls__9, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %ctls__9, i64 -1) - call void @__quantum__rt__qubit_release(%Qubit* %c) - %cc = call %Array* @__quantum__rt__qubit_allocate_array(i64 2) - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 1) - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 1) - %84 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 0) - %85 = bitcast i8* %84 to %Qubit** - %qb__37 = load %Qubit*, %Qubit** %85 - %86 = call i64 @__quantum__rt__array_get_size_1d(%Array* %cc) - %87 = icmp eq i64 %86, 1 - br i1 %87, label %then0__4, label %else__4 - -then0__4: ; preds = %continue__3 - call void @__quantum__qis__single_qubit_op_ctl(i64 1, i64 1, %Array* %cc, %Qubit* %qb__37) - br label %continue__4 - -else__4: ; preds = %continue__3 - call void @__quantum__qis__single_qubit_op_ctl(i64 2, i64 1, %Array* %cc, %Qubit* %qb__37) - br label %continue__4 - -continue__4: ; preds = %else__4, %then0__4 - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 1) - %88 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 0) - %89 = bitcast i8* %88 to %Qubit** - %qb__38 = load %Qubit*, %Qubit** %89 - %90 = icmp eq i64 %86, 1 - br i1 %90, label %then0__5, label %else__5 - -then0__5: ; preds = %continue__4 - call void @__quantum__qis__single_qubit_op_ctl(i64 4, i64 1, %Array* %cc, %Qubit* %qb__38) - br label %continue__5 - -else__5: ; preds = %continue__4 - call void @__quantum__qis__single_qubit_op_ctl(i64 5, i64 1, %Array* %cc, %Qubit* %qb__38) - br label %continue__5 - -continue__5: ; preds = %else__5, %then0__5 - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 1) - %91 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 1) - %92 = bitcast i8* %91 to %Qubit** - %qb__39 = load %Qubit*, %Qubit** %92 - %93 = icmp eq i64 %86, 1 - br i1 %93, label %then0__6, label %else__6 - -then0__6: ; preds = %continue__5 - call void @__quantum__qis__single_qubit_op_ctl(i64 7, i64 1, %Array* %cc, %Qubit* %qb__39) - br label %continue__6 - -else__6: ; preds = %continue__5 - call void @__quantum__qis__single_qubit_op_ctl(i64 8, i64 1, %Array* %cc, %Qubit* %qb__39) - br label %continue__6 - -continue__6: ; preds = %else__6, %then0__6 - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 1) - %94 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 1) - %95 = bitcast i8* %94 to %Qubit** - %qb__40 = load %Qubit*, %Qubit** %95 - call void @__quantum__qis__single_qubit_op_ctl(i64 10, i64 1, %Array* %cc, %Qubit* %qb__40) - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 1) - %96 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 0) - %97 = bitcast i8* %96 to %Qubit** - %qb__41 = load %Qubit*, %Qubit** %97 - call void @__quantum__qis__single_qubit_op_ctl(i64 20, i64 1, %Array* %cc, %Qubit* %qb__41) - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 1) - %98 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 1) - %99 = bitcast i8* %98 to %Qubit** - %qb__42 = load %Qubit*, %Qubit** %99 - call void @__quantum__qis__single_qubit_op_ctl(i64 22, i64 1, %Array* %cc, %Qubit* %qb__42) - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 1) - %100 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 2) - %101 = bitcast i8* %100 to %Qubit** - %qb__43 = load %Qubit*, %Qubit** %101 - call void @__quantum__qis__single_qubit_op_ctl(i64 24, i64 1, %Array* %cc, %Qubit* %qb__43) - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 1) - %102 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 1) - %103 = bitcast i8* %102 to %Qubit** - %qb__44 = load %Qubit*, %Qubit** %103 - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 1) - call void @__quantum__qis__single_qubit_op_ctl(i64 16, i64 1, %Array* %cc, %Qubit* %qb__44) - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 1) - %104 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 2) - %105 = bitcast i8* %104 to %Qubit** - %qb__46 = load %Qubit*, %Qubit** %105 - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 1) - call void @__quantum__qis__single_qubit_op_ctl(i64 12, i64 1, %Array* %cc, %Qubit* %qb__46) - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 -1) - call void @__quantum__rt__qubit_release_array(%Array* %cc) - call void @__quantum__rt__array_update_alias_count(%Array* %cc, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %cc, i64 -1) - call void @__quantum__rt__qubit_release_array(%Array* %qs) - call void @__quantum__rt__array_update_alias_count(%Array* %qs, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %qs, i64 -1) - ret void -} - -declare %Qubit* @__quantum__rt__qubit_allocate() - -declare %Array* @__quantum__rt__qubit_allocate_array(i64) - -declare void @__quantum__qis__inject_barrier(i64, i64) - -declare void @__quantum__rt__qubit_release(%Qubit*) - -declare void @__quantum__rt__qubit_release_array(%Array*) - -define void @Microsoft__Quantum__Testing__Tracer__TestMeasurements__body() { -entry: - %qs = call %Array* @__quantum__rt__qubit_allocate_array(i64 6) - call void @__quantum__rt__array_update_alias_count(%Array* %qs, i64 1) - %0 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 0) - %1 = bitcast i8* %0 to %Qubit** - %qb = load %Qubit*, %Qubit** %1 - call void @__quantum__qis__single_qubit_op(i64 11, i64 1, %Qubit* %qb) - %2 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 0) - %3 = bitcast i8* %2 to %Qubit** - %qb__2 = load %Qubit*, %Qubit** %3 - %r0 = call %Result* @__quantum__qis__single_qubit_measure(i64 100, i64 1, %Qubit* %qb__2) - %4 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 1) - %5 = bitcast i8* %4 to %Qubit** - %qb__4 = load %Qubit*, %Qubit** %5 - call void @__quantum__qis__single_qubit_op(i64 11, i64 1, %Qubit* %qb__4) - %6 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 1) - %7 = bitcast i8* %6 to %Qubit** - %8 = load %Qubit*, %Qubit** %7 - %9 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 2) - %10 = bitcast i8* %9 to %Qubit** - %11 = load %Qubit*, %Qubit** %10 - call void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %8, %Qubit* %11) - %qs12 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 2) - %12 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs12, i64 0) - %13 = bitcast i8* %12 to %Qubit** - %14 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs12, i64 1) - %15 = bitcast i8* %14 to %Qubit** - %16 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 1) - %17 = bitcast i8* %16 to %Qubit** - %18 = load %Qubit*, %Qubit** %17 - %19 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 2) - %20 = bitcast i8* %19 to %Qubit** - %21 = load %Qubit*, %Qubit** %20 - store %Qubit* %18, %Qubit** %13 - store %Qubit* %21, %Qubit** %15 - call void @__quantum__rt__array_update_alias_count(%Array* %qs12, i64 1) - %paulis = call %Array* @__quantum__rt__array_create_1d(i32 1, i64 2) - %22 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 0) - %23 = bitcast i8* %22 to i2* - %24 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 1) - %25 = bitcast i8* %24 to i2* - %26 = load i2, i2* @PauliY - %27 = load i2, i2* @PauliX - store i2 %26, i2* %23 - store i2 %27, i2* %25 - call void @__quantum__rt__array_update_alias_count(%Array* %paulis, i64 1) - call void @__quantum__rt__array_update_alias_count(%Array* %qs12, i64 1) - %28 = load %Result*, %Result** @ResultOne - %res = alloca %Result* - store %Result* %28, %Result** %res - call void @__quantum__rt__result_update_reference_count(%Result* %28, i64 1) - %haveY = alloca i1 - store i1 false, i1* %haveY - br label %header__1 - -header__1: ; preds = %exiting__1, %entry - %i = phi i64 [ 0, %entry ], [ %41, %exiting__1 ] - %29 = icmp sle i64 %i, 1 - br i1 %29, label %body__1, label %exit__1 - -body__1: ; preds = %header__1 - %30 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 %i) - %31 = bitcast i8* %30 to i2* - %32 = load i2, i2* %31 - %33 = load i2, i2* @PauliY - %34 = icmp eq i2 %32, %33 - %35 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 %i) - %36 = bitcast i8* %35 to i2* - %37 = load i2, i2* %36 - %38 = load i2, i2* @PauliI - %39 = icmp eq i2 %37, %38 - %40 = or i1 %34, %39 - br i1 %40, label %then0__1, label %continue__1 - -then0__1: ; preds = %body__1 - store i1 true, i1* %haveY - br label %continue__1 - -continue__1: ; preds = %then0__1, %body__1 - br label %exiting__1 - -exiting__1: ; preds = %continue__1 - %41 = add i64 %i, 1 - br label %header__1 - -exit__1: ; preds = %header__1 - %42 = load i1, i1* %haveY - br i1 %42, label %then0__2, label %test1__1 - -then0__2: ; preds = %exit__1 - %43 = call %Result* @__quantum__qis__joint_measure(i64 106, i64 1, %Array* %qs12) - call void @__quantum__rt__result_update_reference_count(%Result* %43, i64 1) - store %Result* %43, %Result** %res - call void @__quantum__rt__result_update_reference_count(%Result* %43, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %28, i64 -1) - br label %continue__2 - -test1__1: ; preds = %exit__1 - br i1 false, label %then1__1, label %test2__1 - -then1__1: ; preds = %test1__1 - %44 = call %Result* @__quantum__qis__joint_measure(i64 107, i64 1, %Array* %qs12) - call void @__quantum__rt__result_update_reference_count(%Result* %44, i64 1) - %45 = load %Result*, %Result** %res - store %Result* %44, %Result** %res - call void @__quantum__rt__result_update_reference_count(%Result* %44, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %45, i64 -1) - br label %continue__2 - -test2__1: ; preds = %test1__1 - br i1 false, label %then2__1, label %test3__1 - -then2__1: ; preds = %test2__1 - %46 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 0) - %47 = bitcast i8* %46 to i2* - %48 = load i2, i2* %47 - %49 = load i2, i2* @PauliX - %50 = icmp eq i2 %48, %49 - br i1 %50, label %then0__3, label %else__1 - -then0__3: ; preds = %then2__1 - %51 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs12, i64 0) - %52 = bitcast i8* %51 to %Qubit** - %qb__6 = load %Qubit*, %Qubit** %52 - %53 = call %Result* @__quantum__qis__single_qubit_measure(i64 101, i64 1, %Qubit* %qb__6) - call void @__quantum__rt__result_update_reference_count(%Result* %53, i64 1) - %54 = load %Result*, %Result** %res - store %Result* %53, %Result** %res - call void @__quantum__rt__result_update_reference_count(%Result* %53, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %54, i64 -1) - br label %continue__3 - -else__1: ; preds = %then2__1 - %55 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs12, i64 0) - %56 = bitcast i8* %55 to %Qubit** - %qb__7 = load %Qubit*, %Qubit** %56 - %57 = call %Result* @__quantum__qis__single_qubit_measure(i64 100, i64 1, %Qubit* %qb__7) - call void @__quantum__rt__result_update_reference_count(%Result* %57, i64 1) - %58 = load %Result*, %Result** %res - store %Result* %57, %Result** %res - call void @__quantum__rt__result_update_reference_count(%Result* %57, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %58, i64 -1) - br label %continue__3 - -continue__3: ; preds = %else__1, %then0__3 - br label %continue__2 - -test3__1: ; preds = %test2__1 - %59 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 0) - %60 = bitcast i8* %59 to i2* - %61 = load i2, i2* %60 - %62 = load i2, i2* @PauliX - %63 = icmp eq i2 %61, %62 - %64 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 1) - %65 = bitcast i8* %64 to i2* - %66 = load i2, i2* %65 - %67 = load i2, i2* @PauliX - %68 = icmp eq i2 %66, %67 - %69 = and i1 %63, %68 - br i1 %69, label %then3__1, label %test4__1 - -then3__1: ; preds = %test3__1 - call void @__quantum__rt__array_update_alias_count(%Array* %qs12, i64 1) - %70 = call %Result* @__quantum__qis__joint_measure(i64 105, i64 1, %Array* %qs12) - call void @__quantum__rt__array_update_alias_count(%Array* %qs12, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %70, i64 1) - %71 = load %Result*, %Result** %res - store %Result* %70, %Result** %res - call void @__quantum__rt__result_update_reference_count(%Result* %70, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %71, i64 -1) - br label %continue__2 - -test4__1: ; preds = %test3__1 - %72 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 0) - %73 = bitcast i8* %72 to i2* - %74 = load i2, i2* %73 - %75 = load i2, i2* @PauliX - %76 = icmp eq i2 %74, %75 - %77 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 1) - %78 = bitcast i8* %77 to i2* - %79 = load i2, i2* %78 - %80 = load i2, i2* @PauliZ - %81 = icmp eq i2 %79, %80 - %82 = and i1 %76, %81 - br i1 %82, label %then4__1, label %test5__1 - -then4__1: ; preds = %test4__1 - call void @__quantum__rt__array_update_alias_count(%Array* %qs12, i64 1) - %83 = call %Result* @__quantum__qis__joint_measure(i64 103, i64 1, %Array* %qs12) - call void @__quantum__rt__array_update_alias_count(%Array* %qs12, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %83, i64 1) - %84 = load %Result*, %Result** %res - store %Result* %83, %Result** %res - call void @__quantum__rt__result_update_reference_count(%Result* %83, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %84, i64 -1) - br label %continue__2 - -test5__1: ; preds = %test4__1 - %85 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 0) - %86 = bitcast i8* %85 to i2* - %87 = load i2, i2* %86 - %88 = load i2, i2* @PauliZ - %89 = icmp eq i2 %87, %88 - %90 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 1) - %91 = bitcast i8* %90 to i2* - %92 = load i2, i2* %91 - %93 = load i2, i2* @PauliX - %94 = icmp eq i2 %92, %93 - %95 = and i1 %89, %94 - br i1 %95, label %then5__1, label %test6__1 - -then5__1: ; preds = %test5__1 - call void @__quantum__rt__array_update_alias_count(%Array* %qs12, i64 1) - %96 = call %Result* @__quantum__qis__joint_measure(i64 104, i64 1, %Array* %qs12) - call void @__quantum__rt__array_update_alias_count(%Array* %qs12, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %96, i64 1) - %97 = load %Result*, %Result** %res - store %Result* %96, %Result** %res - call void @__quantum__rt__result_update_reference_count(%Result* %96, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %97, i64 -1) - br label %continue__2 - -test6__1: ; preds = %test5__1 - %98 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 0) - %99 = bitcast i8* %98 to i2* - %100 = load i2, i2* %99 - %101 = load i2, i2* @PauliZ - %102 = icmp eq i2 %100, %101 - %103 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %paulis, i64 1) - %104 = bitcast i8* %103 to i2* - %105 = load i2, i2* %104 - %106 = load i2, i2* @PauliZ - %107 = icmp eq i2 %105, %106 - %108 = and i1 %102, %107 - br i1 %108, label %then6__1, label %continue__2 - -then6__1: ; preds = %test6__1 - call void @__quantum__rt__array_update_alias_count(%Array* %qs12, i64 1) - %109 = call %Result* @__quantum__qis__joint_measure(i64 102, i64 1, %Array* %qs12) - call void @__quantum__rt__array_update_alias_count(%Array* %qs12, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %109, i64 1) - %110 = load %Result*, %Result** %res - store %Result* %109, %Result** %res - call void @__quantum__rt__result_update_reference_count(%Result* %109, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %110, i64 -1) - br label %continue__2 - -continue__2: ; preds = %then6__1, %test6__1, %then5__1, %then4__1, %then3__1, %continue__3, %then1__1, %then0__2 - %r12 = load %Result*, %Result** %res - call void @__quantum__rt__array_update_alias_count(%Array* %paulis, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %qs12, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %paulis, i64 -1) - %111 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 3)) - %112 = bitcast %Tuple* %111 to { %Callable*, %Callable*, %Qubit* }* - %113 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %112, i32 0, i32 0 - %114 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %112, i32 0, i32 1 - %115 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %112, i32 0, i32 2 - %116 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Testing__Tracer__Delay, [2 x void (%Tuple*, i64)*]* null, %Tuple* null) - %117 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__X, [2 x void (%Tuple*, i64)*]* null, %Tuple* null) - %118 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 3) - %119 = bitcast i8* %118 to %Qubit** - %120 = load %Qubit*, %Qubit** %119 - store %Callable* %116, %Callable** %113 - store %Callable* %117, %Callable** %114 - store %Qubit* %120, %Qubit** %115 - %121 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @PartialApplication__1, [2 x void (%Tuple*, i64)*]* @MemoryManagement__1, %Tuple* %111) - %122 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 3)) - %123 = bitcast %Tuple* %122 to { %Callable*, %Callable*, %Qubit* }* - %124 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %123, i32 0, i32 0 - %125 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %123, i32 0, i32 1 - %126 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %123, i32 0, i32 2 - %127 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Testing__Tracer__Delay, [2 x void (%Tuple*, i64)*]* null, %Tuple* null) - %128 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__Y, [2 x void (%Tuple*, i64)*]* null, %Tuple* null) - %129 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 3) - %130 = bitcast i8* %129 to %Qubit** - %131 = load %Qubit*, %Qubit** %130 - store %Callable* %127, %Callable** %124 - store %Callable* %128, %Callable** %125 - store %Qubit* %131, %Qubit** %126 - %132 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @PartialApplication__2, [2 x void (%Tuple*, i64)*]* @MemoryManagement__1, %Tuple* %122) - call void @Microsoft__Quantum__Intrinsic__ApplyIfElseIntrinsic__body(%Result* %r0, %Callable* %121, %Callable* %132) - %133 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 3)) - %134 = bitcast %Tuple* %133 to { %Callable*, %Callable*, %Qubit* }* - %135 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %134, i32 0, i32 0 - %136 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %134, i32 0, i32 1 - %137 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %134, i32 0, i32 2 - %138 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Testing__Tracer__Delay, [2 x void (%Tuple*, i64)*]* null, %Tuple* null) - %139 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__Z, [2 x void (%Tuple*, i64)*]* null, %Tuple* null) - %140 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 4) - %141 = bitcast i8* %140 to %Qubit** - %142 = load %Qubit*, %Qubit** %141 - store %Callable* %138, %Callable** %135 - store %Callable* %139, %Callable** %136 - store %Qubit* %142, %Qubit** %137 - %143 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @PartialApplication__3, [2 x void (%Tuple*, i64)*]* @MemoryManagement__1, %Tuple* %133) - %144 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 3)) - %145 = bitcast %Tuple* %144 to { %Callable*, %Callable*, %Qubit* }* - %146 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %145, i32 0, i32 0 - %147 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %145, i32 0, i32 1 - %148 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %145, i32 0, i32 2 - %149 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Testing__Tracer__Delay, [2 x void (%Tuple*, i64)*]* null, %Tuple* null) - %150 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__S, [2 x void (%Tuple*, i64)*]* null, %Tuple* null) - %151 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 4) - %152 = bitcast i8* %151 to %Qubit** - %153 = load %Qubit*, %Qubit** %152 - store %Callable* %149, %Callable** %146 - store %Callable* %150, %Callable** %147 - store %Qubit* %153, %Qubit** %148 - %154 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @PartialApplication__4, [2 x void (%Tuple*, i64)*]* @MemoryManagement__2, %Tuple* %144) - call void @Microsoft__Quantum__Intrinsic__ApplyIfElseIntrinsic__body(%Result* %r12, %Callable* %143, %Callable* %154) - %155 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 5) - %156 = bitcast i8* %155 to %Qubit** - %qb__8 = load %Qubit*, %Qubit** %156 - call void @__quantum__qis__single_qubit_op(i64 19, i64 1, %Qubit* %qb__8) - call void @__quantum__rt__qubit_release_array(%Array* %qs) - call void @__quantum__rt__array_update_alias_count(%Array* %qs, i64 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %qs12, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %qs, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %r0, i64 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %qs12, i64 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %r12, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %121, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %121, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %132, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %132, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %143, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %143, i64 -1) - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %154, i64 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %154, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Testing__Tracer__Delay__body__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Callable*, %Qubit*, %Tuple* }* - %1 = getelementptr inbounds { %Callable*, %Qubit*, %Tuple* }, { %Callable*, %Qubit*, %Tuple* }* %0, i32 0, i32 0 - %2 = getelementptr inbounds { %Callable*, %Qubit*, %Tuple* }, { %Callable*, %Qubit*, %Tuple* }* %0, i32 0, i32 1 - %3 = getelementptr inbounds { %Callable*, %Qubit*, %Tuple* }, { %Callable*, %Qubit*, %Tuple* }* %0, i32 0, i32 2 - %4 = load %Callable*, %Callable** %1 - %5 = load %Qubit*, %Qubit** %2 - %6 = load %Tuple*, %Tuple** %3 - call void @Microsoft__Quantum__Testing__Tracer__Delay__body(%Callable* %4, %Qubit* %5, %Tuple* %6) - ret void -} - -declare %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]*, [2 x void (%Tuple*, i64)*]*, %Tuple*) - -define void @Microsoft__Quantum__Intrinsic__X__body__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Qubit* }* - %1 = getelementptr inbounds { %Qubit* }, { %Qubit* }* %0, i32 0, i32 0 - %2 = load %Qubit*, %Qubit** %1 - call void @Microsoft__Quantum__Intrinsic__X__body(%Qubit* %2) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__X__adj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Qubit* }* - %1 = getelementptr inbounds { %Qubit* }, { %Qubit* }* %0, i32 0, i32 0 - %2 = load %Qubit*, %Qubit** %1 - call void @Microsoft__Quantum__Intrinsic__X__adj(%Qubit* %2) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__X__ctl__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Array*, %Qubit* }* - %1 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 0 - %2 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 1 - %3 = load %Array*, %Array** %1 - %4 = load %Qubit*, %Qubit** %2 - call void @Microsoft__Quantum__Intrinsic__X__ctl(%Array* %3, %Qubit* %4) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__X__ctladj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Array*, %Qubit* }* - %1 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 0 - %2 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 1 - %3 = load %Array*, %Array** %1 - %4 = load %Qubit*, %Qubit** %2 - call void @Microsoft__Quantum__Intrinsic__X__ctladj(%Array* %3, %Qubit* %4) - ret void -} - -define void @Lifted__PartialApplication__1__body__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %capture-tuple to { %Callable*, %Callable*, %Qubit* }* - %1 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %0, i32 0, i32 1 - %2 = load %Callable*, %Callable** %1 - %3 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %0, i32 0, i32 2 - %4 = load %Qubit*, %Qubit** %3 - %5 = bitcast %Tuple* %arg-tuple to { %Tuple* }* - %6 = getelementptr inbounds { %Tuple* }, { %Tuple* }* %5, i32 0, i32 0 - %7 = load %Tuple*, %Tuple** %6 - %8 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 3)) - %9 = bitcast %Tuple* %8 to { %Callable*, %Qubit*, %Tuple* }* - %10 = getelementptr inbounds { %Callable*, %Qubit*, %Tuple* }, { %Callable*, %Qubit*, %Tuple* }* %9, i32 0, i32 0 - %11 = getelementptr inbounds { %Callable*, %Qubit*, %Tuple* }, { %Callable*, %Qubit*, %Tuple* }* %9, i32 0, i32 1 - %12 = getelementptr inbounds { %Callable*, %Qubit*, %Tuple* }, { %Callable*, %Qubit*, %Tuple* }* %9, i32 0, i32 2 - store %Callable* %2, %Callable** %10 - store %Qubit* %4, %Qubit** %11 - store %Tuple* %7, %Tuple** %12 - %13 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %0, i32 0, i32 0 - %14 = load %Callable*, %Callable** %13 - call void @__quantum__rt__callable_invoke(%Callable* %14, %Tuple* %8, %Tuple* %result-tuple) - call void @__quantum__rt__tuple_update_reference_count(%Tuple* %8, i64 -1) - ret void -} - -define void @MemoryManagement__1__RefCount(%Tuple* %capture-tuple, i64 %count-change) { -entry: - %0 = bitcast %Tuple* %capture-tuple to { %Callable*, %Callable*, %Qubit* }* - %1 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %0, i32 0, i32 0 - %2 = load %Callable*, %Callable** %1 - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %2, i64 %count-change) - call void @__quantum__rt__callable_update_reference_count(%Callable* %2, i64 %count-change) - %3 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %0, i32 0, i32 1 - %4 = load %Callable*, %Callable** %3 - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %4, i64 %count-change) - call void @__quantum__rt__callable_update_reference_count(%Callable* %4, i64 %count-change) - call void @__quantum__rt__tuple_update_reference_count(%Tuple* %capture-tuple, i64 %count-change) - ret void -} - -define void @MemoryManagement__1__AliasCount(%Tuple* %capture-tuple, i64 %count-change) { -entry: - %0 = bitcast %Tuple* %capture-tuple to { %Callable*, %Callable*, %Qubit* }* - %1 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %0, i32 0, i32 0 - %2 = load %Callable*, %Callable** %1 - call void @__quantum__rt__callable_memory_management(i32 1, %Callable* %2, i64 %count-change) - call void @__quantum__rt__callable_update_alias_count(%Callable* %2, i64 %count-change) - %3 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %0, i32 0, i32 1 - %4 = load %Callable*, %Callable** %3 - call void @__quantum__rt__callable_memory_management(i32 1, %Callable* %4, i64 %count-change) - call void @__quantum__rt__callable_update_alias_count(%Callable* %4, i64 %count-change) - call void @__quantum__rt__tuple_update_alias_count(%Tuple* %capture-tuple, i64 %count-change) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Y__body__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Qubit* }* - %1 = getelementptr inbounds { %Qubit* }, { %Qubit* }* %0, i32 0, i32 0 - %2 = load %Qubit*, %Qubit** %1 - call void @Microsoft__Quantum__Intrinsic__Y__body(%Qubit* %2) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Y__adj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Qubit* }* - %1 = getelementptr inbounds { %Qubit* }, { %Qubit* }* %0, i32 0, i32 0 - %2 = load %Qubit*, %Qubit** %1 - call void @Microsoft__Quantum__Intrinsic__Y__adj(%Qubit* %2) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Y__ctl__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Array*, %Qubit* }* - %1 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 0 - %2 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 1 - %3 = load %Array*, %Array** %1 - %4 = load %Qubit*, %Qubit** %2 - call void @Microsoft__Quantum__Intrinsic__Y__ctl(%Array* %3, %Qubit* %4) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Y__ctladj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Array*, %Qubit* }* - %1 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 0 - %2 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 1 - %3 = load %Array*, %Array** %1 - %4 = load %Qubit*, %Qubit** %2 - call void @Microsoft__Quantum__Intrinsic__Y__ctladj(%Array* %3, %Qubit* %4) - ret void -} - -define void @Lifted__PartialApplication__2__body__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %capture-tuple to { %Callable*, %Callable*, %Qubit* }* - %1 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %0, i32 0, i32 1 - %2 = load %Callable*, %Callable** %1 - %3 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %0, i32 0, i32 2 - %4 = load %Qubit*, %Qubit** %3 - %5 = bitcast %Tuple* %arg-tuple to { %Tuple* }* - %6 = getelementptr inbounds { %Tuple* }, { %Tuple* }* %5, i32 0, i32 0 - %7 = load %Tuple*, %Tuple** %6 - %8 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 3)) - %9 = bitcast %Tuple* %8 to { %Callable*, %Qubit*, %Tuple* }* - %10 = getelementptr inbounds { %Callable*, %Qubit*, %Tuple* }, { %Callable*, %Qubit*, %Tuple* }* %9, i32 0, i32 0 - %11 = getelementptr inbounds { %Callable*, %Qubit*, %Tuple* }, { %Callable*, %Qubit*, %Tuple* }* %9, i32 0, i32 1 - %12 = getelementptr inbounds { %Callable*, %Qubit*, %Tuple* }, { %Callable*, %Qubit*, %Tuple* }* %9, i32 0, i32 2 - store %Callable* %2, %Callable** %10 - store %Qubit* %4, %Qubit** %11 - store %Tuple* %7, %Tuple** %12 - %13 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %0, i32 0, i32 0 - %14 = load %Callable*, %Callable** %13 - call void @__quantum__rt__callable_invoke(%Callable* %14, %Tuple* %8, %Tuple* %result-tuple) - call void @__quantum__rt__tuple_update_reference_count(%Tuple* %8, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Z__body__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Qubit* }* - %1 = getelementptr inbounds { %Qubit* }, { %Qubit* }* %0, i32 0, i32 0 - %2 = load %Qubit*, %Qubit** %1 - call void @Microsoft__Quantum__Intrinsic__Z__body(%Qubit* %2) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Z__adj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Qubit* }* - %1 = getelementptr inbounds { %Qubit* }, { %Qubit* }* %0, i32 0, i32 0 - %2 = load %Qubit*, %Qubit** %1 - call void @Microsoft__Quantum__Intrinsic__Z__adj(%Qubit* %2) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Z__ctl__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Array*, %Qubit* }* - %1 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 0 - %2 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 1 - %3 = load %Array*, %Array** %1 - %4 = load %Qubit*, %Qubit** %2 - call void @Microsoft__Quantum__Intrinsic__Z__ctl(%Array* %3, %Qubit* %4) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__Z__ctladj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Array*, %Qubit* }* - %1 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 0 - %2 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 1 - %3 = load %Array*, %Array** %1 - %4 = load %Qubit*, %Qubit** %2 - call void @Microsoft__Quantum__Intrinsic__Z__ctladj(%Array* %3, %Qubit* %4) - ret void -} - -define void @Lifted__PartialApplication__3__body__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %capture-tuple to { %Callable*, %Callable*, %Qubit* }* - %1 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %0, i32 0, i32 1 - %2 = load %Callable*, %Callable** %1 - %3 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %0, i32 0, i32 2 - %4 = load %Qubit*, %Qubit** %3 - %5 = bitcast %Tuple* %arg-tuple to { %Tuple* }* - %6 = getelementptr inbounds { %Tuple* }, { %Tuple* }* %5, i32 0, i32 0 - %7 = load %Tuple*, %Tuple** %6 - %8 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 3)) - %9 = bitcast %Tuple* %8 to { %Callable*, %Qubit*, %Tuple* }* - %10 = getelementptr inbounds { %Callable*, %Qubit*, %Tuple* }, { %Callable*, %Qubit*, %Tuple* }* %9, i32 0, i32 0 - %11 = getelementptr inbounds { %Callable*, %Qubit*, %Tuple* }, { %Callable*, %Qubit*, %Tuple* }* %9, i32 0, i32 1 - %12 = getelementptr inbounds { %Callable*, %Qubit*, %Tuple* }, { %Callable*, %Qubit*, %Tuple* }* %9, i32 0, i32 2 - store %Callable* %2, %Callable** %10 - store %Qubit* %4, %Qubit** %11 - store %Tuple* %7, %Tuple** %12 - %13 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %0, i32 0, i32 0 - %14 = load %Callable*, %Callable** %13 - call void @__quantum__rt__callable_invoke(%Callable* %14, %Tuple* %8, %Tuple* %result-tuple) - call void @__quantum__rt__tuple_update_reference_count(%Tuple* %8, i64 -1) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__S__body__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Qubit* }* - %1 = getelementptr inbounds { %Qubit* }, { %Qubit* }* %0, i32 0, i32 0 - %2 = load %Qubit*, %Qubit** %1 - call void @Microsoft__Quantum__Intrinsic__S__body(%Qubit* %2) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__S__adj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Qubit* }* - %1 = getelementptr inbounds { %Qubit* }, { %Qubit* }* %0, i32 0, i32 0 - %2 = load %Qubit*, %Qubit** %1 - call void @Microsoft__Quantum__Intrinsic__S__adj(%Qubit* %2) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__S__ctl__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Array*, %Qubit* }* - %1 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 0 - %2 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 1 - %3 = load %Array*, %Array** %1 - %4 = load %Qubit*, %Qubit** %2 - call void @Microsoft__Quantum__Intrinsic__S__ctl(%Array* %3, %Qubit* %4) - ret void -} - -define void @Microsoft__Quantum__Intrinsic__S__ctladj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %arg-tuple to { %Array*, %Qubit* }* - %1 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 0 - %2 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 1 - %3 = load %Array*, %Array** %1 - %4 = load %Qubit*, %Qubit** %2 - call void @Microsoft__Quantum__Intrinsic__S__ctladj(%Array* %3, %Qubit* %4) - ret void -} - -define void @Lifted__PartialApplication__4__body__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { -entry: - %0 = bitcast %Tuple* %capture-tuple to { %Callable*, %Callable*, %Qubit* }* - %1 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %0, i32 0, i32 1 - %2 = load %Callable*, %Callable** %1 - %3 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %0, i32 0, i32 2 - %4 = load %Qubit*, %Qubit** %3 - %5 = bitcast %Tuple* %arg-tuple to { %Tuple* }* - %6 = getelementptr inbounds { %Tuple* }, { %Tuple* }* %5, i32 0, i32 0 - %7 = load %Tuple*, %Tuple** %6 - %8 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 3)) - %9 = bitcast %Tuple* %8 to { %Callable*, %Qubit*, %Tuple* }* - %10 = getelementptr inbounds { %Callable*, %Qubit*, %Tuple* }, { %Callable*, %Qubit*, %Tuple* }* %9, i32 0, i32 0 - %11 = getelementptr inbounds { %Callable*, %Qubit*, %Tuple* }, { %Callable*, %Qubit*, %Tuple* }* %9, i32 0, i32 1 - %12 = getelementptr inbounds { %Callable*, %Qubit*, %Tuple* }, { %Callable*, %Qubit*, %Tuple* }* %9, i32 0, i32 2 - store %Callable* %2, %Callable** %10 - store %Qubit* %4, %Qubit** %11 - store %Tuple* %7, %Tuple** %12 - %13 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %0, i32 0, i32 0 - %14 = load %Callable*, %Callable** %13 - call void @__quantum__rt__callable_invoke(%Callable* %14, %Tuple* %8, %Tuple* %result-tuple) - call void @__quantum__rt__tuple_update_reference_count(%Tuple* %8, i64 -1) - ret void -} - -define void @MemoryManagement__2__RefCount(%Tuple* %capture-tuple, i64 %count-change) { -entry: - %0 = bitcast %Tuple* %capture-tuple to { %Callable*, %Callable*, %Qubit* }* - %1 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %0, i32 0, i32 0 - %2 = load %Callable*, %Callable** %1 - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %2, i64 %count-change) - call void @__quantum__rt__callable_update_reference_count(%Callable* %2, i64 %count-change) - %3 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %0, i32 0, i32 1 - %4 = load %Callable*, %Callable** %3 - call void @__quantum__rt__callable_memory_management(i32 0, %Callable* %4, i64 %count-change) - call void @__quantum__rt__callable_update_reference_count(%Callable* %4, i64 %count-change) - call void @__quantum__rt__tuple_update_reference_count(%Tuple* %capture-tuple, i64 %count-change) - ret void -} - -define void @MemoryManagement__2__AliasCount(%Tuple* %capture-tuple, i64 %count-change) { -entry: - %0 = bitcast %Tuple* %capture-tuple to { %Callable*, %Callable*, %Qubit* }* - %1 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %0, i32 0, i32 0 - %2 = load %Callable*, %Callable** %1 - call void @__quantum__rt__callable_memory_management(i32 1, %Callable* %2, i64 %count-change) - call void @__quantum__rt__callable_update_alias_count(%Callable* %2, i64 %count-change) - %3 = getelementptr inbounds { %Callable*, %Callable*, %Qubit* }, { %Callable*, %Callable*, %Qubit* }* %0, i32 0, i32 1 - %4 = load %Callable*, %Callable** %3 - call void @__quantum__rt__callable_memory_management(i32 1, %Callable* %4, i64 %count-change) - call void @__quantum__rt__callable_update_alias_count(%Callable* %4, i64 %count-change) - call void @__quantum__rt__tuple_update_alias_count(%Tuple* %capture-tuple, i64 %count-change) - ret void -} - -declare void @__quantum__rt__callable_update_reference_count(%Callable*, i64) - -define { %String* }* @Microsoft__Quantum__Targeting__TargetInstruction__body(%String* %__Item1__) { -entry: - %0 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64)) - %1 = bitcast %Tuple* %0 to { %String* }* - %2 = getelementptr inbounds { %String* }, { %String* }* %1, i32 0, i32 0 - store %String* %__Item1__, %String** %2 - call void @__quantum__rt__string_update_reference_count(%String* %__Item1__, i64 1) - ret { %String* }* %1 -} - -declare void @__quantum__rt__string_update_reference_count(%String*, i64) - -declare void @__quantum__rt__tuple_update_alias_count(%Tuple*, i64) diff --git a/src/QirRuntime/test/unittests/CMakeLists.txt b/src/QirRuntime/test/unittests/CMakeLists.txt deleted file mode 100644 index 29e3357f695..00000000000 --- a/src/QirRuntime/test/unittests/CMakeLists.txt +++ /dev/null @@ -1,29 +0,0 @@ -#============================================================================== -# produce the unit tests binary: qir-runtime-unittests.exe -# -add_executable(qir-runtime-unittests - driver.cpp - QirRuntimeTests.cpp - ToffoliTests.cpp - TracerTests.cpp -) - -target_link_libraries(qir-runtime-unittests PUBLIC - qir-rt-support - qsharp-foundation-qis-support - qsharp-core-qis-support - simulators - tracer -) - -target_include_directories(qir-runtime-unittests PUBLIC - "${test_includes}" - ${public_includes} - "${PROJECT_SOURCE_DIR}/lib/QIR" - "${PROJECT_SOURCE_DIR}/lib/QSharpFoundation" - "${PROJECT_SOURCE_DIR}/lib/QSharpCore" - "${PROJECT_SOURCE_DIR}/lib/Tracer" -) -target_compile_definitions(qir-runtime-unittests PRIVATE EXPORT_QIR_API) -install(TARGETS qir-runtime-unittests RUNTIME DESTINATION "${CMAKE_BINARY_DIR}/bin") -add_unit_test(qir-runtime-unittests) diff --git a/src/Quantum.Development.Kit/Microsoft.Quantum.Development.Kit.nuspec b/src/Quantum.Development.Kit/Microsoft.Quantum.Development.Kit.nuspec index 6a617e3b041..de6a81b711b 100644 --- a/src/Quantum.Development.Kit/Microsoft.Quantum.Development.Kit.nuspec +++ b/src/Quantum.Development.Kit/Microsoft.Quantum.Development.Kit.nuspec @@ -8,13 +8,13 @@ QuantumEngineering, Microsoft MIT - https://docs.microsoft.com/en-us/quantum + https://docs.microsoft.com/azure/quantum images\qdk-nuget-icon.png false Provides tools for developing quantum algorithms in the Q# programming language. - See: https://docs.microsoft.com/en-us/quantum/relnotes/ + See: https://docs.microsoft.com/azure/quantum/qdk-relnotes/ © Microsoft Corporation. All rights reserved. Quantum Q# QSharp diff --git a/src/Simulation/CSharpGeneration.Tests/Circuits/SubDirectory/HelloOther.qs b/src/Simulation/CSharpGeneration.Tests/Circuits/SubDirectory/HelloOther.qs new file mode 100644 index 00000000000..3b7cdc8cf2d --- /dev/null +++ b/src/Simulation/CSharpGeneration.Tests/Circuits/SubDirectory/HelloOther.qs @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Tests.SubDirectory +{ + + operation HelloOther (n : Int) : Int + { + let r = n + 1; + + return r; + } + +} + + diff --git a/src/Simulation/CSharpGeneration.Tests/Circuits/SubDirectory/HelloWorld.qs b/src/Simulation/CSharpGeneration.Tests/Circuits/SubDirectory/HelloWorld.qs new file mode 100644 index 00000000000..ba40ec64cc5 --- /dev/null +++ b/src/Simulation/CSharpGeneration.Tests/Circuits/SubDirectory/HelloWorld.qs @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Tests.SubDirectory +{ + + operation HelloWorld (n : Int) : Int + { + let r = n + 1; + + return r; + } + +} + + diff --git a/src/Simulation/CSharpGeneration.Tests/SimulationCodeTests.fs b/src/Simulation/CSharpGeneration.Tests/SimulationCodeTests.fs index dfe7a2e216d..433b86fa6ed 100644 --- a/src/Simulation/CSharpGeneration.Tests/SimulationCodeTests.fs +++ b/src/Simulation/CSharpGeneration.Tests/SimulationCodeTests.fs @@ -108,10 +108,10 @@ namespace N1 |> failwith let functorGenSuccessful = CodeGeneration.GenerateFunctorSpecializations(compilation, &compilation) // todo: we might want to raise an error here if the functor generation fails (which will be the case for incorrect code) - compilation.Namespaces + compilation with | e -> sprintf "compilation threw exception: \n%s" e.Message |> failwith // should never happen (all exceptions are caught by the compiler) - let syntaxTree = parse [ (Path.Combine("Circuits", "Intrinsic.qs")); (Path.Combine("Circuits", "CodegenTests.qs")) ] + let syntaxTree = parse [ (Path.Combine("Circuits", "Intrinsic.qs")); (Path.Combine("Circuits", "CodegenTests.qs")) ] |> (fun compilation -> compilation.Namespaces) let globalContext = CodegenContext.Create syntaxTree @@ -225,9 +225,9 @@ namespace N1 expected |> (fun s -> s.Replace("%%%", fullPath |> HttpUtility.JavaScriptStringEncode |> escapeCSharpString)) |> (fun s -> s.Replace("%%", fullPath |> escapeCSharpString)) - let tree = parse [Path.Combine ("Circuits", "Intrinsic.qs"); fileName] + let compilation = parse [Path.Combine ("Circuits", "Intrinsic.qs"); fileName] let actual = - CodegenContext.Create (tree, ImmutableDictionary.Empty) + CodegenContext.Create (compilation, ImmutableDictionary.Empty) |> generate (Path.GetFullPath fileName) Assert.Equal(expected |> clearFormatting, actual |> clearFormatting) @@ -248,6 +248,58 @@ namespace N1 List.zip expected actual |> List.iter Assert.Equal<'Z> + [] + let ``testGeneratedFileNames`` () = + + let outputDir = "output" |> Path.GetFullPath + let outputDirSrc = Path.Combine(outputDir, "src") + + let intrinsic = Path.Combine(outputDirSrc, "Intrinsic.g.cs") + let helloWorld = Path.Combine(outputDirSrc, "HelloWorld.g.cs") + let helloWorld1 = Path.Combine(outputDirSrc, "HelloWorld.g1.cs") + let helloOther = Path.Combine(outputDirSrc, "HelloOther.g.cs") + + let deleteFile filePath = + if File.Exists filePath then + File.Delete filePath + + intrinsic |> deleteFile + helloWorld |> deleteFile + helloWorld1 |> deleteFile + helloOther |> deleteFile + + let compilation = parse [ + Path.Combine("Circuits", "Intrinsic.qs") + Path.Combine("Circuits", "HelloWorld.qs") + Path.Combine("Circuits", "SubDirectory", "HelloWorld.qs") + Path.Combine("Circuits", "SubDirectory", "HelloOther.qs") + ] + let transformed = ref { Namespaces = ImmutableArray.Empty; EntryPoints = ImmutableArray.Empty } + let rewriteStep = Emitter() :> IRewriteStep + rewriteStep.AssemblyConstants.Add(AssemblyConstants.OutputPath, outputDir) + rewriteStep.Transformation(compilation, transformed) |> ignore + + let mutable allFilesFound = true + let checkAndDeleteFile filePath = + if File.Exists filePath then + File.Delete filePath + else + allFilesFound <- false + + intrinsic |> checkAndDeleteFile + helloWorld |> checkAndDeleteFile + helloWorld1 |> checkAndDeleteFile + helloOther |> checkAndDeleteFile + + let deleteDir dirPath = + if Directory.Exists dirPath && Directory.EnumerateFileSystemEntries dirPath |> Seq.isEmpty then + Directory.Delete dirPath + + outputDirSrc |> deleteDir + outputDir |> deleteDir + + Assert.True allFilesFound + [] let ``tupleBaseClassName test`` () = let testOne (_, udt) expected = diff --git a/src/Simulation/CSharpGeneration.Tests/Tests.CSharpGeneration.fsproj b/src/Simulation/CSharpGeneration.Tests/Tests.CSharpGeneration.fsproj index 0a421156c67..f19303756a8 100644 --- a/src/Simulation/CSharpGeneration.Tests/Tests.CSharpGeneration.fsproj +++ b/src/Simulation/CSharpGeneration.Tests/Tests.CSharpGeneration.fsproj @@ -8,6 +8,12 @@ + + PreserveNewest + + + PreserveNewest + PreserveNewest diff --git a/src/Simulation/CSharpGeneration/EntryPoint.fs b/src/Simulation/CSharpGeneration/EntryPoint.fs index 4bd9317a3c9..03349ea29e8 100644 --- a/src/Simulation/CSharpGeneration/EntryPoint.fs +++ b/src/Simulation/CSharpGeneration/EntryPoint.fs @@ -26,24 +26,6 @@ let entryPointClassName = "__QsEntryPoint__" /// The namespace containing the non-generated parts of the entry point driver. let private driverNamespace = "Microsoft.Quantum.EntryPointDriver" -/// The driver settings object. -let private driverSettings = - let newDriverSettings = driverNamespace + ".DriverSettings" |> ``type`` |> SyntaxFactory.ObjectCreationExpression - let namedArg (name : string) expr = SyntaxFactory.NameColon name |> (SyntaxFactory.Argument expr).WithNameColon - let immutableList elements = invoke (ident "System.Collections.Immutable.ImmutableList.Create") ``(`` elements ``)`` - let simulatorOptionAliases = - [ literal <| "--" + fst CommandLineArguments.SimulatorOption - literal <| "-" + snd CommandLineArguments.SimulatorOption ] - |> immutableList - [ namedArg "simulatorOptionAliases" simulatorOptionAliases - namedArg "quantumSimulatorName" <| literal AssemblyConstants.QuantumSimulator - namedArg "toffoliSimulatorName" <| literal AssemblyConstants.ToffoliSimulator - namedArg "resourcesEstimatorName" <| literal AssemblyConstants.ResourcesEstimator ] - |> SyntaxFactory.SeparatedList - |> SyntaxFactory.ArgumentList - |> newDriverSettings.WithArgumentList - :> ExpressionSyntax - /// A sequence of all of the named parameters in the argument tuple and their respective C# and Q# types. let rec private parameters context doc = function | QsTupleItem variable -> @@ -75,7 +57,7 @@ let private parameterOptionsProperty parameters = ``property-arrow_get`` optionsEnumerableTypeName "Options" [``public``] get (``=>`` (``new array`` (Some optionTypeName) options)) -/// A method that creates an instance of the default simulator if it is a custom simulator. +/// A lambda that creates an instance of the default simulator if it is a custom simulator. let private customSimulatorFactory name = let isCustomSimulator = not <| List.contains name [ @@ -87,11 +69,7 @@ let private customSimulatorFactory name = if isCustomSimulator then ``new`` (``type`` name) ``(`` [] ``)`` else upcast SyntaxFactory.ThrowExpression (``new`` (``type`` "InvalidOperationException") ``(`` [] ``)``) - - arrow_method "IOperationFactory" "CreateDefaultCustomSimulator" ``<<`` [] ``>>`` - ``(`` [] ``)`` - [``public``] - (Some (``=>`` factory)) + ``() =>`` [] factory :> ExpressionSyntax /// A method that creates the argument tuple for the entry point, given the command-line parsing result. let private createArgument context entryPoint = @@ -119,65 +97,169 @@ let private callableTypeNames context (callable : QsCallable) = let returnTypeName = SimulationCode.roslynTypeName context callable.Signature.ReturnType callableName, argTypeName, returnTypeName -/// The main method for the standalone executable. -let private mainMethod context entryPoint = +/// Generates the class name for an entry point class. +let private entryPointClassFullName (entryPoint : QsCallable) = + { Namespace = entryPoint.FullName.Namespace; Name = entryPointClassName + entryPoint.FullName.Name } + +/// Generates the Submit method for an entry point class. +let private submitMethod context entryPoint = + let callableName, _, _ = callableTypeNames context entryPoint + let parseResultParamName = "parseResult" + let settingsParamName = "settings" + let args = + [ + ident callableName <|.|> ident "Info" + ident "this" <.> (ident "CreateArgument", [ident parseResultParamName]) + ident settingsParamName :> ExpressionSyntax + ] + arrow_method "System.Threading.Tasks.Task" "Submit" ``<<`` [] ``>>`` + ``(`` + [ + param parseResultParamName ``of`` (``type`` "System.CommandLine.Parsing.ParseResult") + param settingsParamName ``of`` (``type`` (driverNamespace + ".AzureSettings")) + ] + ``)`` + [``public``] + (Some (``=>`` (ident (driverNamespace + ".Azure") <.> (ident "Submit", args)))) + +/// Generates the Simulate method for an entry point class. +let private simulateMethod context entryPoint = let callableName, argTypeName, returnTypeName = callableTypeNames context entryPoint - let driverType = generic (driverNamespace + ".Driver") ``<<`` [callableName; argTypeName; returnTypeName] ``>>`` - let entryPointInstance = ``new`` (``type`` entryPointClassName) ``(`` [] ``)`` - let driver = ``new`` driverType ``(`` [driverSettings; entryPointInstance] ``)`` - let commandLineArgsName = "args" - arrow_method "System.Threading.Tasks.Task" "Main" ``<<`` [] ``>>`` - ``(`` [param commandLineArgsName ``of`` (``type`` "string[]")] ``)`` - [``private``; ``static``; async] - (Some (``=>`` (await (driver <.> (ident "Run", [ident commandLineArgsName]))))) + let simulationType = generic (driverNamespace + ".Simulation") ``<<`` [callableName; argTypeName; returnTypeName] ``>>`` + let parseResultParamName = "parseResult" + let settingsParamName = "settings" + let simulatorParamName = "simulator" + let args = + [ + ident "this" :> ExpressionSyntax + ident "this" <.> (ident "CreateArgument", [ident parseResultParamName]) + ident settingsParamName :> ExpressionSyntax + ident simulatorParamName :> ExpressionSyntax + ] + arrow_method "System.Threading.Tasks.Task" "Simulate" ``<<`` [] ``>>`` + ``(`` + [ + param parseResultParamName ``of`` (``type`` "System.CommandLine.Parsing.ParseResult") + param settingsParamName ``of`` (``type`` (driverNamespace + ".DriverSettings")) + param simulatorParamName ``of`` (``type`` "string") + ] + ``)`` + [``public``] + (Some (``=>`` (simulationType <.> (ident "Simulate", args)))) /// The class that adapts the entry point for use with the command-line parsing library and the driver. -let private entryPointClass context entryPoint = - let callableName, argTypeName, returnTypeName = callableTypeNames context entryPoint +let private entryPointClass context (entryPoint : QsCallable) = let property name typeName value = ``property-arrow_get`` typeName name [``public``] get (``=>`` value) + let nameProperty = + entryPoint.FullName.ToString() + |> literal + |> property "Name" "string" let summaryProperty = (PrintSummary entryPoint.Documentation false).Trim () |> literal |> property "Summary" "string" let parameters = parameters context entryPoint.Documentation entryPoint.ArgumentTuple - let defaultSimulator = - context.assemblyConstants.TryGetValue AssemblyConstants.DefaultSimulator - |> fun (_, value) -> if String.IsNullOrWhiteSpace value then AssemblyConstants.QuantumSimulator else value - let defaultSimulatorNameProperty = literal defaultSimulator |> property "DefaultSimulatorName" "string" - let defaultExecutionTargetProperty = - context.assemblyConstants.TryGetValue AssemblyConstants.ExecutionTarget - |> (fun (_, value) -> if value = null then "" else value) - |> literal - |> property "DefaultExecutionTarget" "string" - let infoProperty = - property "Info" (sprintf "EntryPointInfo<%s, %s>" argTypeName returnTypeName) - (ident callableName <|.|> ident "Info") let members : MemberDeclarationSyntax list = [ + nameProperty summaryProperty parameterOptionsProperty parameters - defaultSimulatorNameProperty - defaultExecutionTargetProperty - infoProperty - customSimulatorFactory defaultSimulator createArgument context entryPoint - mainMethod context entryPoint + submitMethod context entryPoint + simulateMethod context entryPoint ] - let baseName = sprintf "%s.IEntryPoint<%s, %s>" driverNamespace argTypeName returnTypeName - ``class`` entryPointClassName``<<`` [] ``>>`` + let baseName = sprintf "%s.IEntryPoint" driverNamespace + ``class`` ((entryPointClassFullName entryPoint).Name) ``<<`` [] ``>>`` ``:`` (Some (simpleBase baseName)) ``,`` [] [``internal``] ``{`` members ``}`` -/// Generates C# source code for a standalone executable that runs the Q# entry point. -let generate context (entryPoint : QsCallable) = - let ns = - ``namespace`` entryPoint.FullName.Namespace +/// Generates a namespace for a set of entry points that share the namespace +let private entryPointNamespace context name entryPoints = + ``namespace`` name + ``{`` + [] + [for ep in entryPoints -> entryPointClass context ep] + ``}`` + +/// Returns the driver settings object. +let private driverSettings context = + let newDriverSettings = driverNamespace + ".DriverSettings" |> ``type`` |> SyntaxFactory.ObjectCreationExpression + let namedArg (name : string) expr = SyntaxFactory.NameColon name |> (SyntaxFactory.Argument expr).WithNameColon + let immutableList elements = invoke (ident "System.Collections.Immutable.ImmutableList.Create") ``(`` elements ``)`` + let simulatorOptionAliases = + [ literal <| "--" + fst CommandLineArguments.SimulatorOption + literal <| "-" + snd CommandLineArguments.SimulatorOption ] + |> immutableList + let defaultSimulator = + context.assemblyConstants.TryGetValue AssemblyConstants.DefaultSimulator + |> fun (_, value) -> if String.IsNullOrWhiteSpace value then AssemblyConstants.QuantumSimulator else value + let defaultExecutionTarget = + context.assemblyConstants.TryGetValue AssemblyConstants.ExecutionTarget + |> (fun (_, value) -> if value = null then "" else value) + |> literal + [ + namedArg "simulatorOptionAliases" simulatorOptionAliases + namedArg "quantumSimulatorName" <| literal AssemblyConstants.QuantumSimulator + namedArg "toffoliSimulatorName" <| literal AssemblyConstants.ToffoliSimulator + namedArg "resourcesEstimatorName" <| literal AssemblyConstants.ResourcesEstimator + namedArg "defaultSimulatorName" <| literal defaultSimulator + namedArg "defaultExecutionTarget" <| defaultExecutionTarget + namedArg "createDefaultCustomSimulator" <| customSimulatorFactory defaultSimulator + ] + |> SyntaxFactory.SeparatedList + |> SyntaxFactory.ArgumentList + |> newDriverSettings.WithArgumentList + :> ExpressionSyntax + +/// The main method for the standalone executable. +let private mainMethod context entryPoints = + + let entryPointArrayMembers = + [ + for ep in entryPoints do + let name = entryPointClassFullName ep + ``new`` (``type`` (name.ToString())) ``(`` [] ``)`` + ] + + let entryPointArray = + ``new array`` (Some (driverNamespace + ".IEntryPoint")) entryPointArrayMembers + + let driver = ``new`` (``type`` (driverNamespace + ".Driver")) ``(`` [driverSettings context; entryPointArray] ``)`` + let commandLineArgsName = "args" + arrow_method "System.Threading.Tasks.Task" "Main" ``<<`` [] ``>>`` + ``(`` [param commandLineArgsName ``of`` (``type`` "string[]")] ``)`` + [``private``; ``static``; async] + (Some (``=>`` (await (driver <.> (ident "Run", [ident commandLineArgsName]))))) + +/// Generates a namespace for the main function +let private mainNamespace context entryPoints = + let mainClass = + ``class`` entryPointClassName ``<<`` [] ``>>`` + ``:`` None ``,`` [] + [``internal``] ``{`` - (Seq.map using SimulationCode.autoNamespaces) - [entryPointClass context entryPoint] + [mainMethod context entryPoints] ``}`` - ``compilation unit`` [] [] [ns] + + ``namespace`` entryPointClassName + ``{`` + [] + [mainClass] + ``}`` + +/// Generates the C# source code for the file containing the Main function. +let generateMainSource context entryPoints = + let mainNS = mainNamespace context entryPoints + ``compilation unit`` [] (Seq.map using SimulationCode.autoNamespaces) [mainNS :> MemberDeclarationSyntax] + |> ``with leading comments`` SimulationCode.autogenComment + |> SimulationCode.formatSyntaxTree + +/// Generates C# source code for a standalone executable that runs the Q# entry point. +let generateSource context (entryPoints : seq) = + let entryPointNamespaces = entryPoints |> Seq.groupBy (fun ep -> ep.FullName.Namespace) + let namespaces = [for ns, eps in entryPointNamespaces -> entryPointNamespace context ns eps :> MemberDeclarationSyntax] + ``compilation unit`` [] (Seq.map using SimulationCode.autoNamespaces) namespaces |> ``with leading comments`` SimulationCode.autogenComment |> SimulationCode.formatSyntaxTree diff --git a/src/Simulation/CSharpGeneration/Microsoft.Quantum.CSharpGeneration.fsproj b/src/Simulation/CSharpGeneration/Microsoft.Quantum.CSharpGeneration.fsproj index 96de234006b..edac14ab0b2 100644 --- a/src/Simulation/CSharpGeneration/Microsoft.Quantum.CSharpGeneration.fsproj +++ b/src/Simulation/CSharpGeneration/Microsoft.Quantum.CSharpGeneration.fsproj @@ -22,7 +22,7 @@ - + diff --git a/src/Simulation/CSharpGeneration/Microsoft.Quantum.CSharpGeneration.nuspec.template b/src/Simulation/CSharpGeneration/Microsoft.Quantum.CSharpGeneration.nuspec.template index 3578f7afcd4..85f8de00fe1 100644 --- a/src/Simulation/CSharpGeneration/Microsoft.Quantum.CSharpGeneration.nuspec.template +++ b/src/Simulation/CSharpGeneration/Microsoft.Quantum.CSharpGeneration.nuspec.template @@ -8,13 +8,13 @@ QuantumEngineering, Microsoft MIT - https://docs.microsoft.com/en-us/quantum + https://docs.microsoft.com/azure/quantum images\qdk-nuget-icon.png false C# code generation for executing Q# programs on a quantum simulator. - See: https://docs.microsoft.com/en-us/quantum/relnotes/ + See: https://docs.microsoft.com/azure/quantum/qdk-relnotes/ $copyright$ Quantum Q# QSharp diff --git a/src/Simulation/CSharpGeneration/RewriteStep.fs b/src/Simulation/CSharpGeneration/RewriteStep.fs index 47e35baf0ca..cd8527bddfa 100644 --- a/src/Simulation/CSharpGeneration/RewriteStep.fs +++ b/src/Simulation/CSharpGeneration/RewriteStep.fs @@ -6,11 +6,9 @@ namespace Microsoft.Quantum.QsCompiler.CsharpGeneration open System open System.Collections.Generic open System.IO -open Microsoft.CodeAnalysis open Microsoft.Quantum.QsCompiler +open Microsoft.Quantum.QsCompiler.CompilationBuilder open Microsoft.Quantum.QsCompiler.CsharpGeneration -open Microsoft.Quantum.QsCompiler.DataTypes -open Microsoft.Quantum.QsCompiler.Diagnostics open Microsoft.Quantum.QsCompiler.ReservedKeywords open Microsoft.Quantum.QsCompiler.SyntaxTree open Microsoft.Quantum.QsCompiler.Transformations.BasicTransformations @@ -19,51 +17,87 @@ open Microsoft.Quantum.QsCompiler.Transformations.BasicTransformations type Emitter() = let _AssemblyConstants = new Dictionary<_, _>() - let mutable _Diagnostics = [] + + let _FileNamesGenerated = new HashSet(); + + [] + let _EnumerationLimit = 100; + + member private this.WriteFile (fileId : string) outputFolder (fileEnding : string) content overwrite = + let mutable fileEnding = fileEnding + let withoutEnding = Path.GetFileNameWithoutExtension(fileId) + let mutable targetFile = Path.GetFullPath(Path.Combine(outputFolder, withoutEnding + fileEnding)) + + if (not overwrite) && _FileNamesGenerated.Contains(targetFile) then + let mutable enumeration = 1 + let pos = fileEnding.LastIndexOf('.') + let (beforeEnumeration, afterEnumeration) = + if pos = -1 + then "", fileEnding + else fileEnding.Substring(0, pos), fileEnding.Substring(pos) + while _FileNamesGenerated.Contains(targetFile) && enumeration < _EnumerationLimit do + fileEnding <- beforeEnumeration + enumeration.ToString() + afterEnumeration + targetFile <- Path.GetFullPath(Path.Combine(outputFolder, withoutEnding + fileEnding)) + enumeration <- enumeration + 1 + + _FileNamesGenerated.Add targetFile |> ignore + File.WriteAllText(targetFile, content) interface IRewriteStep with member this.Name = "CSharpGeneration" member this.Priority = -1 // doesn't matter because this rewrite step is the only one in the dll member this.AssemblyConstants = upcast _AssemblyConstants - member this.GeneratedDiagnostics = upcast _Diagnostics - - member this.ImplementsPreconditionVerification = true + member this.GeneratedDiagnostics = Seq.empty + + member this.ImplementsPreconditionVerification = false member this.ImplementsPostconditionVerification = false member this.ImplementsTransformation = true - member this.PreconditionVerification compilation = - if compilation.EntryPoints.Length > 1 then - _Diagnostics <- IRewriteStep.Diagnostic - (Message = DiagnosticItem.Message (ErrorCode.MultipleEntryPoints, []), - Severity = DiagnosticSeverity.Error, - Stage = IRewriteStep.Stage.PreconditionVerification) :: _Diagnostics - false - else - true - + member this.PreconditionVerification _ = NotImplementedException() |> raise member this.PostconditionVerification _ = NotImplementedException() |> raise - - member this.Transformation (compilation, transformed) = + + member this.Transformation (compilation, transformed) = let step = this :> IRewriteStep - let dir = step.AssemblyConstants.TryGetValue AssemblyConstants.OutputPath |> function - | true, outputFolder when outputFolder <> null -> Path.Combine(outputFolder, "src") - | _ -> step.Name + let dir = + step.AssemblyConstants.TryGetValue AssemblyConstants.OutputPath + |> function + | true, outputFolder when outputFolder <> null -> Path.Combine(outputFolder, "src") + | _ -> step.Name + |> (fun str -> (str.TrimEnd [| Path.DirectorySeparatorChar; Path.AltDirectorySeparatorChar |]) + Path.DirectorySeparatorChar.ToString() |> Uri) + |> (fun uri -> uri.LocalPath |> Path.GetDirectoryName) let context = CodegenContext.Create (compilation, step.AssemblyConstants) - let allSources = GetSourceFiles.Apply compilation.Namespaces + let allSources = GetSourceFiles.Apply compilation.Namespaces + + if (allSources.Count > 0 || not (compilation.EntryPoints.IsEmpty)) && not (Directory.Exists dir) then + Directory.CreateDirectory dir + |> ignore for source in allSources |> Seq.filter context.GenerateCodeForSource do let content = SimulationCode.generate source context - CompilationLoader.GeneratedFile(source, dir, ".g.cs", content) |> ignore + this.WriteFile source dir ".g.cs" content false for source in allSources |> Seq.filter (not << context.GenerateCodeForSource) do let content = SimulationCode.loadedViaTestNames source context - if content <> null then CompilationLoader.GeneratedFile(source, dir, ".dll.g.cs", content) |> ignore + this.WriteFile source dir ".dll.g.cs" content false if not compilation.EntryPoints.IsEmpty then - let callable = context.allCallables.[Seq.exactlyOne compilation.EntryPoints] - let content = EntryPoint.generate context callable - CompilationLoader.GeneratedFile(callable.SourceFile, dir, ".EntryPoint.g.cs", content) |> ignore + + let entryPointCallables = + compilation.EntryPoints + |> Seq.map (fun ep -> context.allCallables.[ep]) + + let entryPointSources = + entryPointCallables + |> Seq.groupBy (fun ep -> ep.Source.CodeFile) + + let mainSourceFile = (dir, "EntryPoint") |> Path.Combine |> Path.GetFullPath |> Uri |> CompilationUnitManager.GetFileId + let content = EntryPoint.generateMainSource context entryPointCallables + this.WriteFile mainSourceFile dir ".g.Main.cs" content false + + for (sourceFile, callables) in entryPointSources do + let content = EntryPoint.generateSource context callables + this.WriteFile sourceFile dir ".g.EntryPoint.cs" content false transformed <- compilation true diff --git a/src/Simulation/Common/AssemblyCommon.props b/src/Simulation/Common/AssemblyCommon.props index 14c45ada66c..abc6491c495 100644 --- a/src/Simulation/Common/AssemblyCommon.props +++ b/src/Simulation/Common/AssemblyCommon.props @@ -5,9 +5,9 @@ Microsoft Microsoft Quantum Development Kit Preview © Microsoft Corporation. All rights reserved. - See: https://docs.microsoft.com/en-us/quantum/relnotes/ + See: https://docs.microsoft.com/azure/quantum/qdk-relnotes/ MIT - https://docs.microsoft.com/quantum/ + https://docs.microsoft.com/azure/quantum/ https://github.com/microsoft/qsharp-runtime qdk-nuget-icon.png true diff --git a/src/Simulation/Common/IQuantumProcessor.cs b/src/Simulation/Common/IQuantumProcessor.cs index ed6d7fcc3eb..8bd4dc6ec7f 100644 --- a/src/Simulation/Common/IQuantumProcessor.cs +++ b/src/Simulation/Common/IQuantumProcessor.cs @@ -563,7 +563,7 @@ public interface IQuantumProcessor void OnFail(System.Runtime.ExceptionServices.ExceptionDispatchInfo exceptionDispatchInfo); /// - /// Called when qubits are allocated by Q# using block. + /// Called when qubits are allocated by Q# using block. /// /// Qubits that are being allocated. /// @@ -573,7 +573,7 @@ public interface IQuantumProcessor void OnAllocateQubits(IQArray qubits); /// - /// Called when qubits are released in Q# in the end of using block. + /// Called when qubits are released in Q# in the end of using block. /// /// Qubits that are being released. /// @@ -583,7 +583,7 @@ public interface IQuantumProcessor void OnReleaseQubits(IQArray qubits); /// - /// Called when qubits are borrowed by Q# borrowing block. + /// Called when qubits are borrowed by Q# borrowing block. /// /// Qubits that are being borrowed. /// Number of qubits that have been allocated for borrowing. This might happen if there have not been enough already allocated qubits available for borrowing.. @@ -594,7 +594,7 @@ public interface IQuantumProcessor void OnBorrowQubits(IQArray qubits, long allocatedForBorrowingCount); /// - /// Called when qubits are returned in the end of Q# borrowing block. + /// Called when qubits are returned in the end of Q# borrowing block. /// /// Qubits that have been borrowed and are now being returned. /// Number of qubits that have been released once returned. This might happen if they have been allocated only for borrowing.. diff --git a/src/Simulation/Common/Simulators.Dev.props b/src/Simulation/Common/Simulators.Dev.props index b4eead59d87..62a9ed4319b 100644 --- a/src/Simulation/Common/Simulators.Dev.props +++ b/src/Simulation/Common/Simulators.Dev.props @@ -31,7 +31,7 @@ - + diff --git a/src/Simulation/Common/Simulators.Test.props b/src/Simulation/Common/Simulators.Test.props index 4e3bcab4ae2..d6085b6b94c 100644 --- a/src/Simulation/Common/Simulators.Test.props +++ b/src/Simulation/Common/Simulators.Test.props @@ -13,6 +13,8 @@ netcoreapp3.1 false false + + false false diff --git a/src/Simulation/EntryPointDriver.Tests/Tests.fs b/src/Simulation/EntryPointDriver.Tests/Tests.fs index 3cfb17f8a14..9ca3ad61330 100644 --- a/src/Simulation/EntryPointDriver.Tests/Tests.fs +++ b/src/Simulation/EntryPointDriver.Tests/Tests.fs @@ -70,10 +70,11 @@ let private compileQSharp source = /// Generates C# source code from the compiled Q# syntax tree using the given assembly constants. let private generateCSharp constants (compilation : QsCompilation) = let context = CodegenContext.Create (compilation, constants) - let entryPoint = context.allCallables.[Seq.exactlyOne compilation.EntryPoints] + let entryPoints = seq { for ep in compilation.EntryPoints -> context.allCallables.[ep] } [ SimulationCode.generate testFile context - EntryPoint.generate context entryPoint + EntryPoint.generateSource context entryPoints + EntryPoint.generateMainSource context entryPoints ] /// The full path to a referenced assembly given its short name. @@ -128,7 +129,7 @@ let private testAssembly testName constants = /// Runs the entry point in the assembly with the given command-line arguments, and returns the output, errors, and exit /// code. let private run (assembly : Assembly) (args : string[]) = - let entryPoint = assembly.GetType (sprintf "%s.%s" testNamespace EntryPoint.entryPointClassName) + let entryPoint = assembly.GetType (sprintf "%s.%s" EntryPoint.entryPointClassName EntryPoint.entryPointClassName) let main = entryPoint.GetMethod("Main", BindingFlags.NonPublic ||| BindingFlags.Static) let previousCulture = CultureInfo.DefaultThreadCurrentCulture let previousOut = Console.Out @@ -191,7 +192,7 @@ let private testWithTarget defaultTarget = |> testWithConstants /// Standard command-line arguments for the "submit" command without specifying a target. -let private submitWithoutTarget = +let private submitWithoutTarget = [ "submit" "--subscription" "mySubscription" @@ -420,7 +421,7 @@ let ``Accepts one-tuple`` () = let given = test "Accepts one-tuple" given ["-x"; "7"; "-y"; "8"] |> yields "7 8" -[] +[] let ``Accepts two-tuple`` () = let given = test "Accepts two-tuple" given ["-x"; "7"; "-y"; "8"; "-z"; "9"] |> yields "7 8 9" @@ -451,7 +452,7 @@ let ``Shadows --simulator`` () = |> yields (sprintf "Warning: Option --simulator is overridden by an entry point parameter name. Using default value QuantumSimulator. %s" AssemblyConstants.ResourcesEstimator) - given ["-s"; AssemblyConstants.ResourcesEstimator; "--simulator"; "foo"] |> fails + given ["-s"; AssemblyConstants.ResourcesEstimator; "--simulator"; "foo"] |> fails given ["-s"; "foo"] |> fails [] @@ -836,6 +837,9 @@ let ``Shows help text for submit command`` () = %s submit [options] Options: + -n (REQUIRED) A number. + --pauli (REQUIRED) The name of a Pauli matrix. + --my-cool-bool (REQUIRED) A neat bit. --subscription (REQUIRED) The subscription ID. --resource-group (REQUIRED) The resource group name. --workspace (REQUIRED) The workspace name. @@ -849,9 +853,6 @@ let ``Shows help text for submit command`` () = --output The information to show in the output after the job is submitted. --dry-run Validate the program and options, but do not submit to Azure Quantum. --verbose Show additional information about the submission. - -n (REQUIRED) A number. - --pauli (REQUIRED) The name of a Pauli matrix. - --my-cool-bool (REQUIRED) A neat bit. -?, -h, --help Show help and usage information" let given = test "Help" given ["submit"; "--help"] |> yields message @@ -865,6 +866,9 @@ let ``Shows help text for submit command with default target`` () = %s submit [options] Options: + -n (REQUIRED) A number. + --pauli (REQUIRED) The name of a Pauli matrix. + --my-cool-bool (REQUIRED) A neat bit. --subscription (REQUIRED) The subscription ID. --resource-group (REQUIRED) The resource group name. --workspace (REQUIRED) The workspace name. @@ -878,9 +882,98 @@ let ``Shows help text for submit command with default target`` () = --output The information to show in the output after the job is submitted. --dry-run Validate the program and options, but do not submit to Azure Quantum. --verbose Show additional information about the submission. - -n (REQUIRED) A number. - --pauli (REQUIRED) The name of a Pauli matrix. - --my-cool-bool (REQUIRED) A neat bit. -?, -h, --help Show help and usage information" let given = testWithTarget "foo.target" "Help" given ["submit"; "--help"] |> yields message + +[] +let ``Supports simulating multiple entry points`` () = + let given = test "Multiple entry points" + given ["simulate"; "EntryPointTest.MultipleEntryPoints1"] |> yields "Hello from Entry Point 1!" + given ["simulate"; "EntryPointTest.MultipleEntryPoints2"] |> yields "Hello from Entry Point 2!" + given ["simulate"; "EntryPointTest3.MultipleEntryPoints3"] |> yields "Hello from Entry Point 3!" + given ["simulate"] |> fails + given [] |> fails + +[] +let ``Supports simulating multiple entry points with different parameters`` () = + let given = test "Multiple entry points with different parameters" + let entryPoint1Args = ["-n"; "42.5"] + let entryPoint2Args = ["-s"; "Hello, World!"] + let entryPoint3Args = ["-i"; "3"] + + given (["simulate"; "EntryPointTest.MultipleEntryPoints1"] @ entryPoint1Args) |> yields "42.5" + given (["simulate"; "EntryPointTest.MultipleEntryPoints1"] @ entryPoint2Args) |> fails + given (["simulate"; "EntryPointTest.MultipleEntryPoints1"] @ entryPoint3Args) |> fails + given ["simulate"; "EntryPointTest.MultipleEntryPoints1"] |> fails + + given (["simulate"; "EntryPointTest.MultipleEntryPoints2"] @ entryPoint1Args) |> fails + given (["simulate"; "EntryPointTest.MultipleEntryPoints2"] @ entryPoint2Args) |> yields "Hello, World!" + given (["simulate"; "EntryPointTest.MultipleEntryPoints2"] @ entryPoint3Args) |> fails + given ["simulate"; "EntryPointTest.MultipleEntryPoints2"] |> fails + + given (["simulate"; "EntryPointTest3.MultipleEntryPoints3"] @ entryPoint1Args) |> fails + given (["simulate"; "EntryPointTest3.MultipleEntryPoints3"] @ entryPoint2Args) |> fails + given (["simulate"; "EntryPointTest3.MultipleEntryPoints3"] @ entryPoint3Args) |> yields "3" + given ["simulate"; "EntryPointTest3.MultipleEntryPoints3"] |> fails + + given ["simulate"] |> fails + given [] |> fails + +[] +let ``Supports submitting multiple entry points`` () = + let options = + [ + "--subscription" + "mySubscription" + "--resource-group" + "myResourceGroup" + "--workspace" + "myWorkspace" + "--target" + "test.nothing" + ] + let given = test "Multiple entry points" + let succeeds = yields "https://www.example.com/00000000-0000-0000-0000-0000000000000" + given (["submit"; "EntryPointTest.MultipleEntryPoints1"] @ options) |> succeeds + given (["submit"; "EntryPointTest.MultipleEntryPoints2"] @ options) |> succeeds + given (["submit"; "EntryPointTest3.MultipleEntryPoints3"] @ options) |> succeeds + given (["submit"] @ options) |> fails + given [] |> fails + +[] +let ``Supports submitting multiple entry points with different parameters`` () = + let options = + [ + "--subscription" + "mySubscription" + "--resource-group" + "myResourceGroup" + "--workspace" + "myWorkspace" + "--target" + "test.nothing" + ] + let entryPoint1Args = ["-n"; "42.5"] + let entryPoint2Args = ["-s"; "Hello, World!"] + let entryPoint3Args = ["-i"; "3"] + let given = test "Multiple entry points with different parameters" + let succeeds = yields "https://www.example.com/00000000-0000-0000-0000-0000000000000" + + given (["submit"; "EntryPointTest.MultipleEntryPoints1"] @ entryPoint1Args @ options) |> succeeds + given (["submit"; "EntryPointTest.MultipleEntryPoints1"] @ entryPoint2Args @ options) |> fails + given (["submit"; "EntryPointTest.MultipleEntryPoints1"] @ entryPoint3Args @ options) |> fails + given (["submit"; "EntryPointTest.MultipleEntryPoints1"] @ options) |> fails + + given (["submit"; "EntryPointTest.MultipleEntryPoints2"] @ entryPoint1Args @ options) |> fails + given (["submit"; "EntryPointTest.MultipleEntryPoints2"] @ entryPoint2Args @ options) |> succeeds + given (["submit"; "EntryPointTest.MultipleEntryPoints2"] @ entryPoint3Args @ options) |> fails + given (["submit"; "EntryPointTest.MultipleEntryPoints2"] @ options) |> fails + + given (["submit"; "EntryPointTest3.MultipleEntryPoints3"] @ entryPoint1Args @ options) |> fails + given (["submit"; "EntryPointTest3.MultipleEntryPoints3"] @ entryPoint2Args @ options) |> fails + given (["submit"; "EntryPointTest3.MultipleEntryPoints3"] @ entryPoint3Args @ options) |> succeeds + given (["submit"; "EntryPointTest3.MultipleEntryPoints3"] @ options) |> fails + + given submitWithNothingTarget |> fails + given [] |> fails diff --git a/src/Simulation/EntryPointDriver.Tests/Tests.qs b/src/Simulation/EntryPointDriver.Tests/Tests.qs index 516f8bca50d..bc05e62be83 100644 --- a/src/Simulation/EntryPointDriver.Tests/Tests.qs +++ b/src/Simulation/EntryPointDriver.Tests/Tests.qs @@ -360,3 +360,49 @@ namespace EntryPointTest { @EntryPoint() operation Help(n : Int, pauli : Pauli, myCoolBool : Bool) : Unit { } } + +// +// Multiple Entry Points +// + +// --- Multiple entry points + +namespace EntryPointTest { + @EntryPoint() + operation MultipleEntryPoints1() : String { + return "Hello from Entry Point 1!"; + } + + @EntryPoint() + operation MultipleEntryPoints2() : String { + return "Hello from Entry Point 2!"; + } +} + +namespace EntryPointTest3 { + @EntryPoint() + operation MultipleEntryPoints3() : String { + return "Hello from Entry Point 3!"; + } +} + +// --- Multiple entry points with different parameters + +namespace EntryPointTest { + @EntryPoint() + operation MultipleEntryPoints1(n : Double) : Double { + return n; + } + + @EntryPoint() + operation MultipleEntryPoints2(s : String) : String { + return s; + } +} + +namespace EntryPointTest3 { + @EntryPoint() + operation MultipleEntryPoints3(i : Int) : Int { + return i; + } +} diff --git a/src/Simulation/EntryPointDriver/Azure.cs b/src/Simulation/EntryPointDriver/Azure.cs index e94624f5602..9f33f7baec5 100644 --- a/src/Simulation/EntryPointDriver/Azure.cs +++ b/src/Simulation/EntryPointDriver/Azure.cs @@ -2,13 +2,13 @@ // Licensed under the MIT License. using System; -using System.CommandLine.Parsing; using System.Linq; using System.Threading.Tasks; using Microsoft.Azure.Quantum; using Microsoft.Azure.Quantum.Exceptions; using Microsoft.Quantum.Runtime; using Microsoft.Quantum.Simulation.Common.Exceptions; +using Microsoft.Quantum.Simulation.Core; using static Microsoft.Quantum.EntryPointDriver.Driver; namespace Microsoft.Quantum.EntryPointDriver @@ -16,19 +16,18 @@ namespace Microsoft.Quantum.EntryPointDriver /// /// Provides entry point submission to Azure Quantum. /// - internal static class Azure + public static class Azure { /// /// Submits the entry point to Azure Quantum. /// - /// The entry point. - /// The command-line parsing result. - /// The submission settings. /// The entry point's argument type. /// The entry point's return type. + /// The information about the entry point. + /// The input argument tuple to the entry point. + /// The submission settings. /// The exit code. - internal static async Task Submit( - IEntryPoint entryPoint, ParseResult parseResult, AzureSettings settings) + public static async Task Submit(EntryPointInfo info, TIn input, AzureSettings settings) { if (settings.Verbose) { @@ -44,28 +43,27 @@ internal static async Task Submit( return 1; } - var input = entryPoint.CreateArgument(parseResult); return settings.DryRun - ? Validate(machine, entryPoint, input) - : await SubmitJob(machine, entryPoint, input, settings); + ? Validate(machine, info, input) + : await SubmitJob(machine, info, input, settings); } /// /// Submits a job to Azure Quantum. /// - /// The quantum machine target. - /// The program entry point. - /// The program input. - /// The submission settings. /// The input type. /// The output type. + /// The quantum machine target. + /// The information about the entry point. + /// The input argument tuple to the entry point. + /// The submission settings. /// The exit code. private static async Task SubmitJob( - IQuantumMachine machine, IEntryPoint entryPoint, TIn input, AzureSettings settings) + IQuantumMachine machine, EntryPointInfo info, TIn input, AzureSettings settings) { try { - var job = await machine.SubmitAsync(entryPoint.Info, input, new SubmissionContext + var job = await machine.SubmitAsync(info, input, new SubmissionContext { FriendlyName = settings.JobName, Shots = settings.Shots @@ -93,15 +91,15 @@ private static async Task SubmitJob( /// /// Validates the program for the quantum machine target. /// - /// The quantum machine target. - /// The program entry point. - /// The program input. /// The input type. /// The output type. + /// The quantum machine target. + /// The information about the entry point. + /// The input argument tuple to the entry point. /// The exit code. - private static int Validate(IQuantumMachine machine, IEntryPoint entryPoint, TIn input) + private static int Validate(IQuantumMachine machine, EntryPointInfo info, TIn input) { - var (isValid, message) = machine.Validate(entryPoint.Info, input); + var (isValid, message) = machine.Validate(info, input); Console.WriteLine(isValid ? "✔️ The program is valid!" : "❌ The program is invalid."); if (!string.IsNullOrWhiteSpace(message)) { @@ -186,7 +184,7 @@ private sealed class SubmissionContext : IQuantumMachineSubmissionContext /// /// The information to show in the output after the job is submitted. /// - internal enum OutputFormat + public enum OutputFormat { /// /// Show a friendly message with a URI that can be used to see the job results. @@ -202,7 +200,7 @@ internal enum OutputFormat /// /// Settings for a submission to Azure Quantum. /// - internal sealed class AzureSettings + public sealed class AzureSettings { /// /// The subscription ID. diff --git a/src/Simulation/EntryPointDriver/Driver.cs b/src/Simulation/EntryPointDriver/Driver.cs index fa521c50b80..7997a87db01 100644 --- a/src/Simulation/EntryPointDriver/Driver.cs +++ b/src/Simulation/EntryPointDriver/Driver.cs @@ -13,66 +13,161 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -using Microsoft.Quantum.Simulation.Core; -using static Microsoft.Quantum.EntryPointDriver.Driver; namespace Microsoft.Quantum.EntryPointDriver { + using Validators = ImmutableList>; + /// - /// The entry point driver is the entry point for the C# application that executes the Q# entry point. + /// The entry point driver is the entry point for the C# application that executes Q# entry points. /// - /// The entry point's callable type. - /// The entry point's argument type. - /// The entry point's return type. - public sealed class Driver where TCallable : AbstractCallable, ICallable + public sealed class Driver { /// - /// The driver settings. + /// The subscription option. /// - private readonly DriverSettings settings; + private static readonly OptionInfo SubscriptionOption = new OptionInfo( + ImmutableList.Create("--subscription"), "The subscription ID."); /// - /// The entry point. + /// The resource group option. /// - private readonly IEntryPoint entryPoint; + private static readonly OptionInfo ResourceGroupOption = new OptionInfo( + ImmutableList.Create("--resource-group"), "The resource group name."); /// - /// The simulator option. + /// The workspace option. + /// + private static readonly OptionInfo WorkspaceOption = new OptionInfo( + ImmutableList.Create("--workspace"), "The workspace name."); + + /// + /// The storage option. + /// + private static readonly OptionInfo StorageOption = new OptionInfo( + ImmutableList.Create("--storage"), default, "The storage account connection string."); + + /// + /// The AAD token option. /// - private OptionInfo SimulatorOption { get; } + private static readonly OptionInfo AadTokenOption = new OptionInfo( + ImmutableList.Create("--aad-token"), default, "The Azure Active Directory authentication token."); + + /// + /// The base URI option. + /// + private static readonly OptionInfo BaseUriOption = new OptionInfo( + ImmutableList.Create("--base-uri"), default, "The base URI of the Azure Quantum endpoint."); + + /// + /// The location to use with the default endpoint option. + /// + private static readonly OptionInfo LocationOption = new OptionInfo( + ImmutableList.Create("--location"), + default, + "The location to use with the default endpoint.", + validator: result => + { + var location = result.Tokens.SingleOrDefault()?.Value; + if (location == null) + { + return default; + } + + var normalizedLocation = AzureSettings.NormalizeLocation(location); + return Uri.CheckHostName(normalizedLocation) == UriHostNameType.Unknown ? + $"\"{location}\" is an invalid value for the --location option." : + default; + }); + + /// + /// The job name option. + /// + private static readonly OptionInfo JobNameOption = new OptionInfo( + ImmutableList.Create("--job-name"), default, "The name of the submitted job."); + + /// + /// The shots option. + /// + private static readonly OptionInfo ShotsOption = new OptionInfo( + ImmutableList.Create("--shots"), + 500, + "The number of times the program is executed on the target machine.", + validator: result => + int.TryParse(result.Tokens.SingleOrDefault()?.Value, out var value) && value <= 0 + ? "The number of shots must be a positive number." + : default); + + /// + /// The output option. + /// + private static readonly OptionInfo OutputOption = new OptionInfo( + ImmutableList.Create("--output"), + OutputFormat.FriendlyUri, + "The information to show in the output after the job is submitted."); + + /// + /// The dry run option. + /// + private static readonly OptionInfo DryRunOption = new OptionInfo( + ImmutableList.Create("--dry-run"), + false, + "Validate the program and options, but do not submit to Azure Quantum."); + + /// + /// The verbose option. + /// + private static readonly OptionInfo VerboseOption = new OptionInfo( + ImmutableList.Create("--verbose"), false, "Show additional information about the submission."); /// /// The target option. /// - private OptionInfo TargetOption { get; } + private readonly OptionInfo TargetOption; + + /// + /// The simulator option. + /// + private readonly OptionInfo SimulatorOption; + + /// + /// The driver settings. + /// + private readonly DriverSettings settings; + + /// + /// All the registered entry points of the program. + /// + private readonly IReadOnlyCollection entryPoints; /// /// Creates a new driver for the entry point. /// /// The driver settings. - /// The entry point. - public Driver(DriverSettings settings, IEntryPoint entryPoint) + /// The entry points. + public Driver(DriverSettings settings, IReadOnlyCollection entryPoints) { this.settings = settings; - this.entryPoint = entryPoint; - SimulatorOption = new OptionInfo( - settings.SimulatorOptionAliases, - entryPoint.DefaultSimulatorName, + this.SimulatorOption = new OptionInfo( + this.settings.SimulatorOptionAliases, + this.settings.DefaultSimulatorName, "The name of the simulator to use.", suggestions: new[] { - settings.QuantumSimulatorName, - settings.ToffoliSimulatorName, - settings.ResourcesEstimatorName, - entryPoint.DefaultSimulatorName + this.settings.QuantumSimulatorName, + this.settings.ToffoliSimulatorName, + this.settings.ResourcesEstimatorName, + this.settings.DefaultSimulatorName }); var targetAliases = ImmutableList.Create("--target"); const string targetDescription = "The target device ID."; - TargetOption = string.IsNullOrWhiteSpace(entryPoint.DefaultExecutionTarget) + this.TargetOption = string.IsNullOrWhiteSpace(settings.DefaultExecutionTarget) ? new OptionInfo(targetAliases, targetDescription) - : new OptionInfo(targetAliases, entryPoint.DefaultExecutionTarget, targetDescription); + : new OptionInfo(targetAliases, this.settings.DefaultExecutionTarget, targetDescription); + + this.entryPoints = entryPoints; } /// @@ -82,46 +177,18 @@ public Driver(DriverSettings settings, IEntryPoint entryPoint) /// The exit code. public async Task Run(string[] args) { - var simulate = new Command("simulate", "(default) Run the program using a local simulator.") - { - Handler = CommandHandler.Create(Simulate) - }; - AddOptionIfAvailable(simulate, SimulatorOption); + var simulateSubCommands = this.entryPoints.Select(this.CreateSimulateEntryPointCommand).ToList(); + var submitSubCommands = this.entryPoints.Select(this.CreateSubmitEntryPointCommand).ToList(); - var submit = new Command("submit", "Submit the program to Azure Quantum.") - { - IsHidden = true, - Handler = CommandHandler.Create(Submit) - }; - AddOptionIfAvailable(submit, SubscriptionOption); - AddOptionIfAvailable(submit, ResourceGroupOption); - AddOptionIfAvailable(submit, WorkspaceOption); - AddOptionIfAvailable(submit, TargetOption); - AddOptionIfAvailable(submit, StorageOption); - AddOptionIfAvailable(submit, AadTokenOption); - AddOptionIfAvailable(submit, BaseUriOption); - AddOptionIfAvailable(submit, LocationOption); - AddOptionIfAvailable(submit, JobNameOption); - AddOptionIfAvailable(submit, ShotsOption); - AddOptionIfAvailable(submit, OutputOption); - AddOptionIfAvailable(submit, DryRunOption); - AddOptionIfAvailable(submit, VerboseOption); - MarkOptionsAsMutuallyExclusive( - submit, - new[] { BaseUriOption.Aliases.First(), LocationOption.Aliases.First() }); - - var root = new RootCommand(entryPoint.Summary) { simulate, submit }; - foreach (var option in entryPoint.Options) - { - root.AddGlobalOption(option); - } + var simulate = CreateSimulateCommand(simulateSubCommands); + var submit = CreateSubmitCommand(submitSubCommands); - // Set the simulate command as the default. - foreach (var option in simulate.Options) + var root = new RootCommand() { simulate.Command, submit.Command }; + if (this.entryPoints.Count() == 1) { - root.AddOption(option); + SetSubCommandAsDefault(root, simulate.Command, simulate.Validators); + root.Description = this.entryPoints.First().Summary; } - root.Handler = simulate.Handler; Console.OutputEncoding = Encoding.UTF8; return await new CommandLineBuilder(root) @@ -132,57 +199,59 @@ public async Task Run(string[] args) } /// - /// Simulates the entry point. + /// Displays a message to the console using the given color and text writer. /// - /// The command-line parsing result. - /// The simulator to use. - /// The exit code. - private async Task Simulate(ParseResult parseResult, string simulator) => - await Simulation.Simulate( - settings, entryPoint, parseResult, DefaultIfShadowed(SimulatorOption, simulator)); + /// The text color. + /// The text writer for the console output stream. + /// The message to display. + internal static void DisplayWithColor(ConsoleColor color, TextWriter writer, string message) + { + var originalForeground = Console.ForegroundColor; + Console.ForegroundColor = color; + writer.WriteLine(message); + Console.ForegroundColor = originalForeground; + } /// - /// Submits the entry point to Azure Quantum. + /// Copies the handle and options from the given sub command to the given command. /// - /// The command-line parsing result. - /// The Azure submission settings. - private async Task Submit(ParseResult parseResult, AzureSettings azureSettings) => - await Azure.Submit(entryPoint, parseResult, new AzureSettings + /// The command whose handle and options will be set. + /// The sub command that will be copied from. + /// The validators associated with the sub command. + private static void SetSubCommandAsDefault(Command root, Command subCommand, Validators validators) + { + root.Handler = subCommand.Handler; + foreach (var option in subCommand.Options) { - Subscription = azureSettings.Subscription, - ResourceGroup = azureSettings.ResourceGroup, - Workspace = azureSettings.Workspace, - Target = DefaultIfShadowed(TargetOption, azureSettings.Target), - Storage = DefaultIfShadowed(StorageOption, azureSettings.Storage), - AadToken = DefaultIfShadowed(AadTokenOption, azureSettings.AadToken), - BaseUri = DefaultIfShadowed(BaseUriOption, azureSettings.BaseUri), - Location = DefaultIfShadowed(LocationOption, azureSettings.Location), - JobName = DefaultIfShadowed(JobNameOption, azureSettings.JobName), - Shots = DefaultIfShadowed(ShotsOption, azureSettings.Shots), - Output = DefaultIfShadowed(OutputOption, azureSettings.Output), - DryRun = DefaultIfShadowed(DryRunOption, azureSettings.DryRun), - Verbose = DefaultIfShadowed(VerboseOption, azureSettings.Verbose) - }); + root.AddOption(option); + } + foreach (var validator in validators) + { + root.AddValidator(validator); + } + } /// - /// Returns true if the alias is not already used by an entry point option. + /// Returns true if the alias is not already used by an existing option. /// /// The alias to check. + /// Existing options to check against. /// True if the alias is available for use by the driver. - private bool IsAliasAvailable(string alias) => - !entryPoint.Options.SelectMany(option => option.RawAliases).Contains(alias); + private static bool IsAliasAvailable(string alias, IEnumerable + /// The type of the option's argument. /// The command to add the option to. /// The option to add. - /// The type of the option's argument. - private void AddOptionIfAvailable(Command command, OptionInfo option) + /// The list of validators added to the command during this function. + private static Validators AddOptionIfAvailable(Command command, OptionInfo option) { - if (IsAliasAvailable(option.Aliases.First())) + if (IsAliasAvailable(option.Aliases.First(), command.Options)) { - command.AddOption(option.Create(option.Aliases.Where(IsAliasAvailable))); + command.AddOption(option.Create(option.Aliases.Where(alias => IsAliasAvailable(alias, command.Options)))); } else if (option.Required) { - command.AddValidator(commandResult => - $"The required option {option.Aliases.First()} conflicts with an entry point parameter name."); + ValidateSymbol validator = commandResult => + $"The required option {option.Aliases.First()} conflicts with an entry point parameter name."; + + command.AddValidator(validator); + return ImmutableList.Create(validator); } + + return Validators.Empty; } /// @@ -220,8 +295,10 @@ private void AddOptionIfAvailable(Command command, OptionInfo option) /// /// The command to add the validator to. /// The primary aliases of the options to be marked as mutually exclusive. - private void MarkOptionsAsMutuallyExclusive(Command command, string[] primaryAliases) => - command.AddValidator(result => + /// The list of validators added to the command during this function. + private static Validators MarkOptionsAsMutuallyExclusive(Command command, string[] primaryAliases) + { + ValidateSymbol validator = result => { var presentAliases = new List(); foreach (var rawAlias in primaryAliases) @@ -241,146 +318,194 @@ private void MarkOptionsAsMutuallyExclusive(Command command, string[] primaryAli } return default; - }); - } - - /// - /// Static members for . - /// - internal static class Driver - { - // TODO: Define the aliases as constants. - - /// - /// The subscription option. - /// - internal static readonly OptionInfo SubscriptionOption = new OptionInfo( - ImmutableList.Create("--subscription"), "The subscription ID."); - - /// - /// The resource group option. - /// - internal static readonly OptionInfo ResourceGroupOption = new OptionInfo( - ImmutableList.Create("--resource-group"), "The resource group name."); - - /// - /// The workspace option. - /// - internal static readonly OptionInfo WorkspaceOption = new OptionInfo( - ImmutableList.Create("--workspace"), "The workspace name."); - - /// - /// The storage option. - /// - internal static readonly OptionInfo StorageOption = new OptionInfo( - ImmutableList.Create("--storage"), default, "The storage account connection string."); + }; - /// - /// The AAD token option. - /// - internal static readonly OptionInfo AadTokenOption = new OptionInfo( - ImmutableList.Create("--aad-token"), default, "The Azure Active Directory authentication token."); + command.AddValidator(validator); + return ImmutableList.Create(validator); + } /// - /// The base URI option. + /// Creates the simulate command. /// - internal static readonly OptionInfo BaseUriOption = new OptionInfo( - ImmutableList.Create("--base-uri"), default, "The base URI of the Azure Quantum endpoint."); + /// The entry point commands that will be the sub commands to the created command. + /// The created simulate command with the validators for that command. + private static CommandWithValidators CreateSimulateCommand( + List entryPointCommands) + { + var simulate = new Command("simulate", "(default) Run the program using a local simulator."); + if (entryPointCommands.Count() == 1) + { + var epCommandWValidators = entryPointCommands.First(); + epCommandWValidators.Command.IsHidden = true; + simulate.AddCommand(epCommandWValidators.Command); + SetSubCommandAsDefault(simulate, epCommandWValidators.Command, epCommandWValidators.Validators); + return new CommandWithValidators(simulate, epCommandWValidators.Validators); + } + else + { + foreach (var epCommandWValidators in entryPointCommands) + { + simulate.AddCommand(epCommandWValidators.Command); + } + return new CommandWithValidators(simulate, Validators.Empty); + } + } /// - /// The location to use with the default endpoint option. + /// Creates the Azure submit command. /// - internal static readonly OptionInfo LocationOption = new OptionInfo( - ImmutableList.Create("--location"), - default, - "The location to use with the default endpoint.", - validator: result => + /// The entry point commands that will be the sub commands to the created command. + /// The created submit command with the validators for that command. + private static CommandWithValidators CreateSubmitCommand(List entryPointCommands) + { + var submit = new Command("submit", "Submit the program to Azure Quantum.") + { + IsHidden = true, + }; + if (entryPointCommands.Count() == 1) + { + var epCommandWValidators = entryPointCommands.First(); + epCommandWValidators.Command.IsHidden = true; + submit.AddCommand(epCommandWValidators.Command); + SetSubCommandAsDefault(submit, epCommandWValidators.Command, epCommandWValidators.Validators); + return new CommandWithValidators(submit, epCommandWValidators.Validators); + } + else + { + foreach (var epCommandWValidators in entryPointCommands) { - var location = result.Tokens.SingleOrDefault()?.Value; - if (location == null) - { - return default; - } - - var normalizedLocation = AzureSettings.NormalizeLocation(location); - return Uri.CheckHostName(normalizedLocation) == UriHostNameType.Unknown ? - $"\"{location}\" is an invalid value for the --location option." : - default; - }); + submit.AddCommand(epCommandWValidators.Command); + } + return new CommandWithValidators(submit, Validators.Empty); + } + } /// - /// The job name option. + /// Creates a sub command specific to the given entry point for the simulate command. /// - internal static readonly OptionInfo JobNameOption = new OptionInfo( - ImmutableList.Create("--job-name"), default, "The name of the submitted job."); + /// The entry point to make a command for. + /// The command corresponding to the given entry point with the validators for that command. + private CommandWithValidators CreateSimulateEntryPointCommand(IEntryPoint entryPoint) + { + var command = new Command(entryPoint.Name, entryPoint.Summary) + { + Handler = CommandHandler.Create((ParseResult parseResult, string simulator) => this.Simulate(parseResult, simulator, entryPoint)) + }; + foreach (var option in entryPoint.Options) + { + command.AddOption(option); + } + return new CommandWithValidators(command, AddOptionIfAvailable(command, this.SimulatorOption)); + } /// - /// The shots option. + /// Creates a sub command specific to the given entry point for the submit command. /// - internal static readonly OptionInfo ShotsOption = new OptionInfo( - ImmutableList.Create("--shots"), - 500, - "The number of times the program is executed on the target machine.", - validator: result => - int.TryParse(result.Tokens.SingleOrDefault()?.Value, out var value) && value <= 0 - ? "The number of shots must be a positive number." - : default); + /// The entry point to make a command for. + /// The command corresponding to the given entry point with the validators for that command. + private CommandWithValidators CreateSubmitEntryPointCommand(IEntryPoint entryPoint) + { + var command = new Command(entryPoint.Name, entryPoint.Summary) + { + Handler = CommandHandler.Create((ParseResult parseResult, AzureSettings settings) => this.Submit(parseResult, settings, entryPoint)) + }; + foreach (var option in entryPoint.Options) + { + command.AddOption(option); + } - /// - /// The output option. - /// - internal static readonly OptionInfo OutputOption = new OptionInfo( - ImmutableList.Create("--output"), - OutputFormat.FriendlyUri, - "The information to show in the output after the job is submitted."); + var validators = AddOptionIfAvailable(command, SubscriptionOption) + .Concat(AddOptionIfAvailable(command, ResourceGroupOption)) + .Concat(AddOptionIfAvailable(command, WorkspaceOption)) + .Concat(AddOptionIfAvailable(command, this.TargetOption)) + .Concat(AddOptionIfAvailable(command, StorageOption)) + .Concat(AddOptionIfAvailable(command, AadTokenOption)) + .Concat(AddOptionIfAvailable(command, BaseUriOption)) + .Concat(AddOptionIfAvailable(command, LocationOption)) + .Concat(AddOptionIfAvailable(command, JobNameOption)) + .Concat(AddOptionIfAvailable(command, ShotsOption)) + .Concat(AddOptionIfAvailable(command, OutputOption)) + .Concat(AddOptionIfAvailable(command, DryRunOption)) + .Concat(AddOptionIfAvailable(command, VerboseOption)) + .Concat(MarkOptionsAsMutuallyExclusive( + command, + new[] { BaseUriOption.Aliases.First(), LocationOption.Aliases.First() })); + + return new CommandWithValidators(command, validators.ToImmutableList()); + } /// - /// The dry run option. + /// Simulates the entry point. /// - internal static readonly OptionInfo DryRunOption = new OptionInfo( - ImmutableList.Create("--dry-run"), - false, - "Validate the program and options, but do not submit to Azure Quantum."); + /// The command-line parsing result. + /// The simulator to use. + /// The entry point to simulate. + /// The exit code. + private Task Simulate(ParseResult parseResult, string simulator, IEntryPoint entryPoint) => + entryPoint.Simulate(parseResult, settings, DefaultIfShadowed(entryPoint, this.SimulatorOption, simulator)); /// - /// The verbose option. + /// Submits the entry point to Azure Quantum. /// - internal static readonly OptionInfo VerboseOption = new OptionInfo( - ImmutableList.Create("--verbose"), false, "Show additional information about the submission."); - + /// The command-line parsing result. + /// The Azure submission settings. + /// The entry point to submit. + /// The exit code. + private Task Submit(ParseResult parseResult, AzureSettings azureSettings, IEntryPoint entryPoint) => + entryPoint.Submit(parseResult, new AzureSettings + { + Subscription = azureSettings.Subscription, + ResourceGroup = azureSettings.ResourceGroup, + Workspace = azureSettings.Workspace, + Target = DefaultIfShadowed(entryPoint, this.TargetOption, azureSettings.Target), + Storage = DefaultIfShadowed(entryPoint, StorageOption, azureSettings.Storage), + AadToken = DefaultIfShadowed(entryPoint, AadTokenOption, azureSettings.AadToken), + BaseUri = DefaultIfShadowed(entryPoint, BaseUriOption, azureSettings.BaseUri), + Location = DefaultIfShadowed(entryPoint, LocationOption, azureSettings.Location), + JobName = DefaultIfShadowed(entryPoint, JobNameOption, azureSettings.JobName), + Shots = DefaultIfShadowed(entryPoint, ShotsOption, azureSettings.Shots), + Output = DefaultIfShadowed(entryPoint, OutputOption, azureSettings.Output), + DryRun = DefaultIfShadowed(entryPoint, DryRunOption, azureSettings.DryRun), + Verbose = DefaultIfShadowed(entryPoint, VerboseOption, azureSettings.Verbose) + }); + /// - /// Displays a message to the console using the given color and text writer. + /// A modification of the command-line class. /// - /// The text color. - /// The text writer for the console output stream. - /// The message to display. - internal static void DisplayWithColor(ConsoleColor color, TextWriter writer, string message) + private sealed class QsHelpBuilder : HelpBuilder { - var originalForeground = Console.ForegroundColor; - Console.ForegroundColor = color; - writer.WriteLine(message); - Console.ForegroundColor = originalForeground; + /// + /// Creates a new help builder using the given console. + /// + /// The console to use. + internal QsHelpBuilder(IConsole console) : base(console) + { + } + + protected override string ArgumentDescriptor(IArgument argument) + { + // Hide long argument descriptors. + var descriptor = base.ArgumentDescriptor(argument); + return descriptor.Length > 30 ? argument.Name : descriptor; + } } - } - /// - /// A modification of the command-line class. - /// - internal sealed class QsHelpBuilder : HelpBuilder - { /// - /// Creates a new help builder using the given console. + /// Struct for housing a command with its validators. /// - /// The console to use. - internal QsHelpBuilder(IConsole console) : base(console) + private struct CommandWithValidators { - } + public Command Command; + public Validators Validators; - protected override string ArgumentDescriptor(IArgument argument) - { - // Hide long argument descriptors. - var descriptor = base.ArgumentDescriptor(argument); - return descriptor.Length > 30 ? argument.Name : descriptor; + /// + /// Basic constructor. + /// + public CommandWithValidators(Command command, Validators validators) + { + Command = command; + Validators = validators; + } } } } diff --git a/src/Simulation/EntryPointDriver/DriverSettings.cs b/src/Simulation/EntryPointDriver/DriverSettings.cs index 17ec8e551a3..cd2402b12d8 100644 --- a/src/Simulation/EntryPointDriver/DriverSettings.cs +++ b/src/Simulation/EntryPointDriver/DriverSettings.cs @@ -1,4 +1,6 @@ -using System.Collections.Immutable; +using Microsoft.Quantum.Simulation.Core; +using System; +using System.Collections.Immutable; namespace Microsoft.Quantum.EntryPointDriver { @@ -27,6 +29,25 @@ public sealed class DriverSettings /// internal string ResourcesEstimatorName { get; } + /// + /// The name of the default simulator to use when simulating the entry point. + /// + internal string DefaultSimulatorName { get; } + + /// + /// The default execution target when to use when submitting the entry point to Azure Quantum. + /// + internal string DefaultExecutionTarget { get; } + + /// + /// Creates an instance of the default simulator if it is a custom simulator. + /// + /// An instance of the default custom simulator. + /// + /// Thrown if the default simulator is not a custom simulator. + /// + internal Func CreateDefaultCustomSimulator; + /// /// Creates a new driver settings instance. /// @@ -34,16 +55,25 @@ public sealed class DriverSettings /// The name of the quantum simulator. /// The name of the Toffoli simulator. /// The name of the resources estimator. + /// The name of the default simulator to use. + /// The name of the default execution target to use. + /// The function for creating a new instance of the default simulator if it is a custom simulator. public DriverSettings( IImmutableList simulatorOptionAliases, string quantumSimulatorName, string toffoliSimulatorName, - string resourcesEstimatorName) + string resourcesEstimatorName, + string defaultSimulatorName, + string defaultExecutionTarget, + Func createDefaultCustomSimulator) { SimulatorOptionAliases = simulatorOptionAliases; QuantumSimulatorName = quantumSimulatorName; ToffoliSimulatorName = toffoliSimulatorName; ResourcesEstimatorName = resourcesEstimatorName; + DefaultSimulatorName = defaultSimulatorName; + DefaultExecutionTarget = defaultExecutionTarget; + CreateDefaultCustomSimulator = createDefaultCustomSimulator; } } } diff --git a/src/Simulation/EntryPointDriver/IEntryPoint.cs b/src/Simulation/EntryPointDriver/IEntryPoint.cs index 1018fc10f89..67964abb05d 100644 --- a/src/Simulation/EntryPointDriver/IEntryPoint.cs +++ b/src/Simulation/EntryPointDriver/IEntryPoint.cs @@ -1,11 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -using System; using System.Collections.Generic; using System.CommandLine; using System.CommandLine.Parsing; -using Microsoft.Quantum.Simulation.Core; +using System.Threading.Tasks; namespace Microsoft.Quantum.EntryPointDriver { @@ -16,10 +15,13 @@ namespace Microsoft.Quantum.EntryPointDriver /// Contains entry point properties needed by the command-line interface and allows the entry point to use /// command-line arguments. The implementation of this interface is code-generated. /// - /// The entry point's argument type. - /// The entry point's return type. - public interface IEntryPoint + public interface IEntryPoint { + /// + /// The name of the entry point. + /// + string Name { get; } + /// /// The summary from the entry point's documentation comment. /// @@ -31,34 +33,20 @@ public interface IEntryPoint IEnumerable