diff --git a/bootstrap.ps1 b/bootstrap.ps1 index c0498281eb0..44db7e6c17a 100644 --- a/bootstrap.ps1 +++ b/bootstrap.ps1 @@ -19,7 +19,7 @@ Push-Location (Join-Path $PSScriptRoot "./src/Simulation/qdk_sim_rs") --version $Env:NUGET_VERSION; Pop-Location -if (-not (Test-Path Env:AGENT_OS)) { # If not CI build, i.e. local build (if AGENT_OS envvar is not defined) +if (-not (Test-Path Env:/AGENT_OS)) { # If not CI build, i.e. local build (if AGENT_OS envvar is not defined) if ($Env:ENABLE_NATIVE -ne "false") { Write-Host "Build release flavor of the native simulator" $Env:BUILD_CONFIGURATION = "Release" diff --git a/build/ci-codecheck.yml b/build/ci-codecheck.yml new file mode 100644 index 00000000000..4b4545f31e8 --- /dev/null +++ b/build/ci-codecheck.yml @@ -0,0 +1,37 @@ +name: $(date:yyMM).$(DayOfMonth)$(rev:rr) + +trigger: none + +pr: +- main +- feature/* +- features/* +- release/* + +schedules: +- cron: "0 9 * * Sat" + displayName: 'Build for Component Governance' + branches: + include: + - main + always: true + +variables: + CI: "true" + +jobs: +- job: build + displayName: Build + strategy: + matrix: + linux: + imageName: 'ubuntu-latest' + mac: + imageName: 'macOS-latest' + #windows: # No sanitizers supported on Win at the moment. + # imageName: 'windows-latest' + pool: + vmImage: $(imageName) + + steps: + - template: steps-codecheck.yml diff --git a/build/steps-codecheck.yml b/build/steps-codecheck.yml new file mode 100644 index 00000000000..8a25efe684f --- /dev/null +++ b/build/steps-codecheck.yml @@ -0,0 +1,50 @@ +## +# Run all build steps. +## +steps: + +- task: NuGetToolInstaller@0 + displayName: 'Use NuGet 5.6.0' + inputs: + versionSpec: '5.6.0' + + # QIR Runtime: +- pwsh: src/Qir/Runtime/prerequisites.ps1 + displayName: "Install QIR Runtime Prerequisistes" + workingDirectory: $(System.DefaultWorkingDirectory) + +- pwsh: src/Qir/Runtime/build-qir-runtime.ps1 + displayName: "Build QIR Runtime" + workingDirectory: $(System.DefaultWorkingDirectory) + +- pwsh: src/Qir/Runtime/test-qir-runtime.ps1 + displayName: "Test QIR Runtime" + workingDirectory: $(System.DefaultWorkingDirectory) + + # Native Simulator (needed to build and run the QIR tests): +- pwsh: src/Simulation/Native/prerequisites.ps1 + displayName: "Install Native Simulator Prerequisites" + workingDirectory: $(System.DefaultWorkingDirectory) + +- powershell: | + .\build-native-simulator.ps1 + displayName: "Build Native Simulator" + workingDirectory: $(System.DefaultWorkingDirectory)/src/Simulation/Native + + # QIR Tests: +- pwsh: src/Qir/Tests/build-qir-tests.ps1 + displayName: "Build QIR Tests" + workingDirectory: $(System.DefaultWorkingDirectory) + +- pwsh: src/Qir/Tests/test-qir-tests.ps1 + displayName: "Run QIR Tests" + workingDirectory: $(System.DefaultWorkingDirectory) + + # QIR Samples: +- pwsh: src/Qir/Samples/build-qir-samples.ps1 + displayName: "Build QIR Samples" + workingDirectory: $(System.DefaultWorkingDirectory) + +- pwsh: src/Qir/Samples/test-qir-samples.ps1 + displayName: "Run QIR Samples" + workingDirectory: $(System.DefaultWorkingDirectory) diff --git a/src/Azure/Azure.Quantum.Client.Test/Authentication/TokenFileCredentialTests.cs b/src/Azure/Azure.Quantum.Client.Test/Authentication/TokenFileCredentialTests.cs index 79dfc462af0..8a3d8a95a6c 100644 --- a/src/Azure/Azure.Quantum.Client.Test/Authentication/TokenFileCredentialTests.cs +++ b/src/Azure/Azure.Quantum.Client.Test/Authentication/TokenFileCredentialTests.cs @@ -49,19 +49,19 @@ public class TokenFileCredentialTests [TestInitialize] public void TestInitialize() { - Environment.SetEnvironmentVariable("AZUREQUANTUM_TOKEN_FILE", _tokenFilePath); + Environment.SetEnvironmentVariable("AZURE_QUANTUM_TOKEN_FILE", _tokenFilePath); } [TestCleanup] public void TestCleanup() { - Environment.SetEnvironmentVariable("AZUREQUANTUM_TOKEN_FILE", null); + Environment.SetEnvironmentVariable("AZURE_QUANTUM_TOKEN_FILE", null); } [TestMethod] public void Test_WhenFileNotSet_Throws_CredentialUnavailableException() { - Environment.SetEnvironmentVariable("AZUREQUANTUM_TOKEN_FILE", null); + Environment.SetEnvironmentVariable("AZURE_QUANTUM_TOKEN_FILE", null); var credential = new TokenFileCredential(); var exception = Assert.ThrowsException(() => diff --git a/src/Azure/Azure.Quantum.Client.Test/WorkspaceTest.cs b/src/Azure/Azure.Quantum.Client.Test/WorkspaceTest.cs index 2b631603705..9f8a6935233 100644 --- a/src/Azure/Azure.Quantum.Client.Test/WorkspaceTest.cs +++ b/src/Azure/Azure.Quantum.Client.Test/WorkspaceTest.cs @@ -24,10 +24,10 @@ public class WorkspaceTest { private const string SETUP = @" Live tests require you to configure your environment with these variables: - * AZUREQUANTUM_WORKSPACE_NAME: the name of an Azure Quantum workspace to use for live testing. - * AZUREQUANTUM_SUBSCRIPTION_ID: the Azure Quantum workspace's Subscription Id. - * AZUREQUANTUM_WORKSPACE_RG: the Azure Quantum workspace's resource group. - * AZUREQUANTUM_WORKSPACE_LOCATION: the Azure Quantum workspace's location (region). + * AZURE_QUANTUM_WORKSPACE_NAME: the name of an Azure Quantum workspace to use for live testing. + * AZURE_QUANTUM_SUBSCRIPTION_ID: the Azure Quantum workspace's Subscription Id. + * AZURE_QUANTUM_WORKSPACE_RG: the Azure Quantum workspace's resource group. + * AZURE_QUANTUM_WORKSPACE_LOCATION: the Azure Quantum workspace's location (region). We'll also try to authenticate with Azure using an instance of DefaultCredential. See https://docs.microsoft.com/en-us/dotnet/api/overview/azure/identity-readme#authenticate-the-client @@ -187,24 +187,24 @@ private static void AssertJob(CloudJob job) private IWorkspace GetLiveWorkspace() { - if (string.IsNullOrWhiteSpace(System.Environment.GetEnvironmentVariable("AZUREQUANTUM_SUBSCRIPTION_ID")) || - string.IsNullOrWhiteSpace(System.Environment.GetEnvironmentVariable("AZUREQUANTUM_WORKSPACE_RG")) || - string.IsNullOrWhiteSpace(System.Environment.GetEnvironmentVariable("AZUREQUANTUM_WORKSPACE_NAME")) || - string.IsNullOrWhiteSpace(System.Environment.GetEnvironmentVariable("AZUREQUANTUM_SUBSCRIPTION_ID"))) + if (string.IsNullOrWhiteSpace(System.Environment.GetEnvironmentVariable("AZURE_QUANTUM_SUBSCRIPTION_ID")) || + string.IsNullOrWhiteSpace(System.Environment.GetEnvironmentVariable("AZURE_QUANTUM_WORKSPACE_RG")) || + string.IsNullOrWhiteSpace(System.Environment.GetEnvironmentVariable("AZURE_QUANTUM_WORKSPACE_NAME")) || + string.IsNullOrWhiteSpace(System.Environment.GetEnvironmentVariable("AZURE_QUANTUM_SUBSCRIPTION_ID"))) { Assert.Inconclusive(SETUP); } var options = new QuantumJobClientOptions(); - options.Diagnostics.ApplicationId = "ClientTests"; + options.Diagnostics.ApplicationId = Environment.GetEnvironmentVariable("AZURE_QUANTUM_NET_APPID") ?? "ClientTests"; var credential = Authentication.CredentialFactory.CreateCredential(Authentication.CredentialType.Default); return new Workspace( - subscriptionId: System.Environment.GetEnvironmentVariable("AZUREQUANTUM_SUBSCRIPTION_ID"), - resourceGroupName: System.Environment.GetEnvironmentVariable("AZUREQUANTUM_WORKSPACE_RG"), - workspaceName: System.Environment.GetEnvironmentVariable("AZUREQUANTUM_WORKSPACE_NAME"), - location: System.Environment.GetEnvironmentVariable("AZUREQUANTUM_WORKSPACE_LOCATION"), + subscriptionId: System.Environment.GetEnvironmentVariable("AZURE_QUANTUM_SUBSCRIPTION_ID"), + resourceGroupName: System.Environment.GetEnvironmentVariable("AZURE_QUANTUM_WORKSPACE_RG"), + workspaceName: System.Environment.GetEnvironmentVariable("AZURE_QUANTUM_WORKSPACE_NAME"), + location: System.Environment.GetEnvironmentVariable("AZURE_QUANTUM_WORKSPACE_LOCATION"), options: options, credential: credential); } diff --git a/src/Azure/Azure.Quantum.Client/Authentication/TokenFileCredential.cs b/src/Azure/Azure.Quantum.Client/Authentication/TokenFileCredential.cs index 6b889c9ae5f..49a8e6c3036 100644 --- a/src/Azure/Azure.Quantum.Client/Authentication/TokenFileCredential.cs +++ b/src/Azure/Azure.Quantum.Client/Authentication/TokenFileCredential.cs @@ -17,7 +17,7 @@ namespace Microsoft.Azure.Quantum.Authentication /// /// Implements a custom TokenCredential to use a local file as the source for an AzureQuantum token. /// - /// It will only use the local file if the AZUREQUANTUM_TOKEN_FILE environment variable is set, and references + /// It will only use the local file if the AZURE_QUANTUM_TOKEN_FILE environment variable is set, and references /// an existing json file that contains the access_token and expires_on timestamp in milliseconds. /// /// If the environment variable is not set, the file does not exist, or the token is invalid in any way(expired, for example), @@ -28,7 +28,7 @@ public class TokenFileCredential : TokenCredential /// /// Environment variable name for the token file path. /// - private const string TokenFileEnvironmentVariable = "AZUREQUANTUM_TOKEN_FILE"; + private const string TokenFileEnvironmentVariable = "AZURE_QUANTUM_TOKEN_FILE"; /// /// File system dependency injected so that unit testing is possible. diff --git a/src/Azure/Azure.Quantum.Client/JobManagement/Workspace.cs b/src/Azure/Azure.Quantum.Client/JobManagement/Workspace.cs index e6c9a7e1f97..e4015ee75e8 100644 --- a/src/Azure/Azure.Quantum.Client/JobManagement/Workspace.cs +++ b/src/Azure/Azure.Quantum.Client/JobManagement/Workspace.cs @@ -51,6 +51,8 @@ public class Workspace : IWorkspace // Optional parameters: credential ??= CredentialFactory.CreateCredential(CredentialType.Default, subscriptionId); options ??= new QuantumJobClientOptions(); + options.Diagnostics.ApplicationId = options.Diagnostics.ApplicationId + ?? Environment.GetEnvironmentVariable("AZURE_QUANTUM_NET_APPID"); this.ResourceGroupName = resourceGroupName; this.WorkspaceName = workspaceName; diff --git a/src/Qir/.clang-tidy b/src/Qir/.clang-tidy index 8fb71d1375a..184f559ddff 100644 --- a/src/Qir/.clang-tidy +++ b/src/Qir/.clang-tidy @@ -1,5 +1,11 @@ Checks: - '-*,bugprone-*,-readability-*,readability-identifier-*,readability-braces-around-statements' + 'bugprone-*,readability-identifier-*,readability-braces-around-statements,cert*,\ + -llvmlibc-callee-namespace,-llvmlibc-implementation-in-namespace,\ + -llvmlibc-restrict-system-libc-headers,-modernize-use-trailing-return-type,\ + -fuchsia-default-arguments-calls,-fuchsia-default-arguments-declarations, + -google-readability-casting' +# TODO(rokuzmin): '*, . . .' + WarningsAsErrors: '*' HeaderFilterRegex: '.*' diff --git a/src/Qir/CommandLineTool/Program.cs b/src/Qir/CommandLineTool/Program.cs index 9e61e65ae1a..85a09c8cb59 100644 --- a/src/Qir/CommandLineTool/Program.cs +++ b/src/Qir/CommandLineTool/Program.cs @@ -42,10 +42,14 @@ private static Command CreateBuildCommand() { var buildCommand = new Command("build", "(default) Build the executables from a QIR DLL.") { - Handler = CommandHandler.Create((BuildOptions settings) => - QirTools.BuildFromQSharpDll(settings.QSharpDll, settings.LibraryDirectories, settings.IncludeDirectories, settings.ExecutablesDirectory)) + Handler = CommandHandler.Create((BuildOptions settings) => QirTools.BuildFromQSharpDll( + settings.QSharpDll, + settings.LibraryDirectories, + settings.IncludeDirectories, + settings.ExecutablesDirectory, + settings.Debug)), + TreatUnmatchedTokensAsErrors = true }; - buildCommand.TreatUnmatchedTokensAsErrors = true; buildCommand.AddOption(new Option( aliases: new string[] { "--qsharp-dll", "--dll" }, @@ -83,6 +87,10 @@ private static Command CreateBuildCommand() Required = true }); + buildCommand.AddOption(new Option( + alias: "--debug", + description: "Enable additional debugging checks at runtime.")); + return buildCommand; } @@ -145,6 +153,11 @@ public sealed class BuildOptions /// The path to the output directory where the created executables will be placed. /// public DirectoryInfo ExecutablesDirectory { get; set; } + + /// + /// Enable additional debugging checks at runtime. + /// + public bool Debug { get; set; } } } } diff --git a/src/Qir/Runtime/lib/QIR/.clang-tidy b/src/Qir/Runtime/lib/QIR/.clang-tidy deleted file mode 100644 index 8268b75c21d..00000000000 --- a/src/Qir/Runtime/lib/QIR/.clang-tidy +++ /dev/null @@ -1 +0,0 @@ -Checks: '-*,bugprone-*' \ No newline at end of file diff --git a/src/Qir/Runtime/lib/QIR/CMakeLists.txt b/src/Qir/Runtime/lib/QIR/CMakeLists.txt index 08a30df8cfd..f7ef19d24ed 100644 --- a/src/Qir/Runtime/lib/QIR/CMakeLists.txt +++ b/src/Qir/Runtime/lib/QIR/CMakeLists.txt @@ -9,7 +9,6 @@ # create qir-rt-support lib from the C++ sources # set(rt_sup_source_files - QirRange.cpp OutputStream.cpp Output.cpp allocationsTracker.cpp diff --git a/src/Qir/Runtime/lib/QIR/Output.cpp b/src/Qir/Runtime/lib/QIR/Output.cpp index ce2f6bf41d8..67e6a4e3e36 100644 --- a/src/Qir/Runtime/lib/QIR/Output.cpp +++ b/src/Qir/Runtime/lib/QIR/Output.cpp @@ -6,7 +6,7 @@ // Public API: extern "C" { - void quantum__rt__message(QirString* qstr) // NOLINT + void __quantum__rt__message(QirString* qstr) // NOLINT { Microsoft::Quantum::OutputStream::Get() << qstr->str << std::endl; } diff --git a/src/Qir/Runtime/lib/QIR/QirRange.cpp b/src/Qir/Runtime/lib/QIR/QirRange.cpp deleted file mode 100644 index d6758352aab..00000000000 --- a/src/Qir/Runtime/lib/QIR/QirRange.cpp +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -#include -#include "QirTypes.hpp" -#include "QirRuntime.hpp" - -QirRange::QirRange(int64_t st, int64_t sp, int64_t en) - // clang-format off - : start(st) - , step(sp) - , end(en) -// clang-format on -{ - // An attempt to create a %Range with a zero step should cause a runtime failure. - // https://github.com/microsoft/qsharp-language/blob/main/Specifications/QIR/Data-Types.md#simple-types - if (sp == 0) - { - quantum__rt__fail_cstr("Attempt to create a range with 0 step"); - } -} diff --git a/src/Qir/Runtime/lib/QIR/QubitManager.cpp b/src/Qir/Runtime/lib/QIR/QubitManager.cpp index 86bd7fecf54..9e44aaf33e0 100644 --- a/src/Qir/Runtime/lib/QIR/QubitManager.cpp +++ b/src/Qir/Runtime/lib/QIR/QubitManager.cpp @@ -16,14 +16,14 @@ namespace Quantum [[noreturn]] static void FailNow(const char* message) { - quantum__rt__fail_cstr(message); + __quantum__rt__fail_cstr(message); } static void FailIf(bool condition, const char* message) { if (condition) { - quantum__rt__fail_cstr(message); + __quantum__rt__fail_cstr(message); } } @@ -181,8 +181,8 @@ namespace Quantum sharedQubitStatusArray = new QubitIdType[(size_t)qubitCapacity]; // These objects are passed by value (copies are created) - QubitListInSharedArray FreeQubitsFresh(0, qubitCapacity - 1, sharedQubitStatusArray); - RestrictedReuseArea outermostArea(FreeQubitsFresh); + QubitListInSharedArray freeQubitsFresh(0, qubitCapacity - 1, sharedQubitStatusArray); + RestrictedReuseArea outermostArea(freeQubitsFresh); freeQubitsInAreas.PushToBack(outermostArea); freeQubitCount = qubitCapacity; @@ -431,7 +431,7 @@ namespace Quantum // existing values (NonMarker or indexes in the array). // Prepare new shared status array - QubitIdType* newStatusArray = new QubitIdType[(size_t)requestedCapacity]; + auto* newStatusArray = new QubitIdType[(size_t)requestedCapacity]; memcpy(newStatusArray, sharedQubitStatusArray, (size_t)qubitCapacity * sizeof(newStatusArray[0])); QubitListInSharedArray newFreeQubits(qubitCapacity, requestedCapacity - 1, newStatusArray); diff --git a/src/Qir/Runtime/lib/QIR/README.md b/src/Qir/Runtime/lib/QIR/README.md index 8e3c54ab7a0..600d8c22d1c 100644 --- a/src/Qir/Runtime/lib/QIR/README.md +++ b/src/Qir/Runtime/lib/QIR/README.md @@ -17,7 +17,7 @@ Same-level entities are independent of each other (unless specified otherwise). **public\QirTypes.hpp** Defines `QirArray`, `QirString`, `PTuple`, `QirTupleHeader`, `TupleWithControls`, `QirCallable`, `QirRange`. Depends on the listed earlier ones. -**public\QirRuntime.hpp** Declares `quantum__rt__*()`. Depends on the listed earlier ones. +**public\QirRuntime.hpp** Declares `__quantum__rt__*()`. Depends on the listed earlier ones. ## Level 1 @@ -25,17 +25,17 @@ Same-level entities are independent of each other (unless specified otherwise). **allocationsTracker.hpp** Defines `Microsoft::Quantum::AllocationsTracker` that tracks the allocations and detects the mem leaks. Does not depend on anything of our code. -**utils.cpp** Implements `quantum__rt__fail()`, `quantum__rt__memory_allocate()`, `quantum__rt__heap_{alloc,free}()`. - `quantum__rt__heap_alloc()` calls **strings.cpp**'s `quantum__rt__string_create()` - cyclical dependency. +**utils.cpp** Implements `__quantum__rt__fail()`, `__quantum__rt__memory_allocate()`, `__quantum__rt__heap_{alloc,free}()`. + `__quantum__rt__heap_alloc()` calls **strings.cpp**'s `__quantum__rt__string_create()` - cyclical dependency. -**strings.cpp** Implements `QirString`, `quantum__rt__string_*()`, `quantum__rt___to_string()` (except `qubit_to_string` and `result_to_string`). - Depends on **utils.cpp**'s `quantum__rt__fail()` - cyclical dependency. +**strings.cpp** Implements `QirString`, `__quantum__rt__string_*()`, `__quantum__rt___to_string()` (except `qubit_to_string` and `result_to_string`). + Depends on **utils.cpp**'s `__quantum__rt__fail()` - cyclical dependency. ## Level 2 **allocationsTracker.cpp** Implements the internals of `Microsoft::Quantum::AllocationsTracker`. - Depends on `quantum__rt__fail()`, `quantum__rt__string_create()` + Depends on `__quantum__rt__fail()`, `__quantum__rt__string_create()` **context.cpp** Implements the internals of `Microsoft::Quantum::QirExecutionContext`, Depends on **allocationsTracker.hpp**'s `Microsoft::Quantum::AllocationsTracker`. @@ -43,24 +43,17 @@ Same-level entities are independent of each other (unless specified otherwise). ## Level 3 -**delegated.cpp** Implements `quantum__rt__result_*()`, `quantum__rt__qubit_{allocate,release,to_string}()`. +**delegated.cpp** Implements `__quantum__rt__result_*()`, `__quantum__rt__qubit_{allocate,release,to_string}()`. Each API depends on `Microsoft::Quantum::GlobalContext()[->GetDriver()]`, - `quantum__rt__qubit_to_string()` also depends on strings.cpp's `quantum__rt__string_create()`. - `quantum__rt__result_to_string()` also depends on strings.cpp's `quantum__rt__string_create()`. + `__quantum__rt__qubit_to_string()` also depends on strings.cpp's `__quantum__rt__string_create()`. + `__quantum__rt__result_to_string()` also depends on strings.cpp's `__quantum__rt__string_create()`. -**arrays.cpp** Implements {the internals of `QirArray`} and `quantum__rt__*array*`. - Depends on `Microsoft::Quantum::GlobalContext()`, `quantum__rt__fail()`, `quantum__rt__string_create()`, - **delegated.cpp**'s `quantum__rt__qubit_allocate()` +**arrays.cpp** Implements {the internals of `QirArray`} and `__quantum__rt__*array*`. + Depends on `Microsoft::Quantum::GlobalContext()`, `__quantum__rt__fail()`, `__quantum__rt__string_create()`, + **delegated.cpp**'s `__quantum__rt__qubit_allocate()` ## Level 4 -**callables.cpp** Defines the {internals of `QirTupleHeader`, `QirCallable`}, `quantum__rt__tuple_*()`, `quantum__rt__callable_*()` - Depends on `QirArray`, `Microsoft::Quantum::GlobalContext()`, `quantum__rt__fail()`, `quantum__rt__string_create()`, `TupleWithControls`, +**callables.cpp** Defines the {internals of `QirTupleHeader`, `QirCallable`}, `__quantum__rt__tuple_*()`, `__quantum__rt__callable_*()` + Depends on `QirArray`, `Microsoft::Quantum::GlobalContext()`, `__quantum__rt__fail()`, `__quantum__rt__string_create()`, `TupleWithControls`, Consider breaking up into **Tuples.cpp** and **Callables.cpp**. - -## Level 5 - -**bridge-rt.ll** Defines the `@__quantum__rt__*` entry points (to be called by the `.ll` files generated from users' `.qs` files). - The C++ Standard reserves the identifiers starting with double underscores `__`, that is why the definitions of `@__quantum__rt__*` - have been put to `.ll` file rather than `.cpp` file. - Depends on `quantum__rt__*` implementations (in **utils.cpp**, **strings.cpp**, **delegated.cpp**, **arrays.cpp**, **callables.cpp**). diff --git a/src/Qir/Runtime/lib/QIR/allocationsTracker.cpp b/src/Qir/Runtime/lib/QIR/allocationsTracker.cpp index fc32fd97217..e9b516c2646 100644 --- a/src/Qir/Runtime/lib/QIR/allocationsTracker.cpp +++ b/src/Qir/Runtime/lib/QIR/allocationsTracker.cpp @@ -20,7 +20,7 @@ namespace Quantum { if (inserted.first->second > 0) { - quantum__rt__fail_cstr("Allocating an object over an existing object!"); + __quantum__rt__fail_cstr("Allocating an object over an existing object!"); } else { @@ -34,13 +34,13 @@ namespace Quantum auto tracked = this->allocatedObjects.find(object); if (tracked == this->allocatedObjects.end()) { - quantum__rt__fail_cstr("Attempting to addref an object that isn't tracked!"); + __quantum__rt__fail_cstr("Attempting to addref an object that isn't tracked!"); } else { if (tracked->second <= 0) { - quantum__rt__fail_cstr("Attempting to ressurect a previously released object!"); + __quantum__rt__fail_cstr("Attempting to ressurect a previously released object!"); } else { @@ -54,13 +54,13 @@ namespace Quantum auto tracked = this->allocatedObjects.find(object); if (tracked == this->allocatedObjects.end()) { - quantum__rt__fail_cstr("Attempting to release an object that isn't tracked!"); + __quantum__rt__fail_cstr("Attempting to release an object that isn't tracked!"); } else { if (tracked->second <= 0) { - quantum__rt__fail_cstr("Attempting to release a previously released object!"); + __quantum__rt__fail_cstr("Attempting to release a previously released object!"); } else { @@ -75,7 +75,7 @@ namespace Quantum { if (tracked.second > 0) { - quantum__rt__fail_cstr("Found a potentially leaked object!"); + __quantum__rt__fail_cstr("Found a potentially leaked object!"); } } } diff --git a/src/Qir/Runtime/lib/QIR/arrays.cpp b/src/Qir/Runtime/lib/QIR/arrays.cpp index fa50441ea75..15859dc6629 100644 --- a/src/Qir/Runtime/lib/QIR/arrays.cpp +++ b/src/Qir/Runtime/lib/QIR/arrays.cpp @@ -54,8 +54,8 @@ int QirArray::Release() return rc; } -QirArray::QirArray(TItemCount qubits_count) - : count(qubits_count) +QirArray::QirArray(TItemCount qubitsCount) + : count(qubitsCount) , itemSizeInBytes((TItemSize)sizeof(void*)) , ownsQubits(true) , refCount(1) @@ -65,7 +65,7 @@ QirArray::QirArray(TItemCount qubits_count) Qubit* qbuffer = new Qubit[count]; for (TItemCount i = 0; i < count; i++) { - qbuffer[i] = quantum__rt__qubit_allocate(); + qbuffer[i] = __quantum__rt__qubit_allocate(); } this->buffer = reinterpret_cast(qbuffer); } @@ -81,25 +81,25 @@ QirArray::QirArray(TItemCount qubits_count) } } -QirArray::QirArray(TItemCount count_items, TItemSize item_size_bytes, TDimCount dimCount, TDimContainer&& dimSizes) - : count(count_items) +QirArray::QirArray(TItemCount countItems, TItemSize itemSizeBytes, TDimCount dimCount, TDimContainer&& dimSizes) + : count(countItems) // Each array item needs to be properly aligned. Let's align them by correcting the `itemSizeInBytes`. , itemSizeInBytes( - ((item_size_bytes == 1) || (item_size_bytes == 2) || (item_size_bytes == 4) || - ((item_size_bytes % sizeof(size_t)) == 0) // For built-in types or multiples of architecture alignment + ((itemSizeBytes == 1) || (itemSizeBytes == 2) || (itemSizeBytes == 4) || + ((itemSizeBytes % sizeof(size_t)) == 0) // For built-in types or multiples of architecture alignment ) - ? item_size_bytes // leave their natural alignment. - // Other types align on the architecture boundary `sizeof(size_t)`: - // 4 bytes on 32-bit arch, 8 on 64-bit arch. - : item_size_bytes + sizeof(size_t) - (item_size_bytes % sizeof(size_t))) + ? itemSizeBytes // leave their natural alignment. + // Other types align on the architecture boundary `sizeof(size_t)`: + // 4 bytes on 32-bit arch, 8 on 64-bit arch. + : itemSizeBytes + sizeof(size_t) - (itemSizeBytes % sizeof(size_t))) , dimensions(dimCount) , dimensionSizes(std::move(dimSizes)) , ownsQubits(false) , refCount(1) { - assert(item_size_bytes != 0); + assert(itemSizeBytes != 0); assert(dimCount > 0); if (GlobalContext() != nullptr) @@ -112,18 +112,18 @@ QirArray::QirArray(TItemCount count_items, TItemSize item_size_bytes, TDimCount assert(this->dimensionSizes.empty() || this->dimensionSizes[0] == this->count); if (this->dimensionSizes.empty()) { - this->dimensionSizes.push_back(count_items); + this->dimensionSizes.push_back(countItems); } } assert(this->count * (TBufSize)itemSizeInBytes < std::numeric_limits::max()); // Using `<` rather than `<=` to calm down the compiler on 32-bit arch. - const TBufSize buffer_size = this->count * itemSizeInBytes; - if (buffer_size > 0) + const TBufSize bufferSize = this->count * itemSizeInBytes; + if (bufferSize > 0) { - this->buffer = new char[buffer_size]; - assert(buffer_size <= std::numeric_limits::max()); - memset(this->buffer, 0, (size_t)buffer_size); + this->buffer = new char[bufferSize]; + assert(bufferSize <= std::numeric_limits::max()); + memset(this->buffer, 0, (size_t)bufferSize); } else { @@ -178,26 +178,26 @@ void QirArray::Append(const QirArray* other) assert((TBufSize)(other->count) * other->itemSizeInBytes < std::numeric_limits::max()); // Using `<` rather than `<=` to calm down the compiler on 32-bit arch. - const TBufSize other_size = other->count * other->itemSizeInBytes; + const TBufSize otherSize = other->count * other->itemSizeInBytes; - if (other_size == 0) + if (otherSize == 0) { return; } assert((TBufSize)(this->count) * this->itemSizeInBytes < std::numeric_limits::max()); // Using `<` rather than `<=` to calm down the compiler on 32-bit arch. - const TBufSize this_size = this->count * this->itemSizeInBytes; + const TBufSize thisSize = this->count * this->itemSizeInBytes; - char* new_buffer = new char[this_size + other_size]; - if (this_size) + char* newBuffer = new char[thisSize + otherSize]; + if (thisSize) { - memcpy(new_buffer, this->buffer, this_size); + memcpy(newBuffer, this->buffer, thisSize); } - memcpy(&new_buffer[this_size], other->buffer, other_size); + memcpy(&newBuffer[thisSize], other->buffer, otherSize); delete[] this->buffer; - this->buffer = new_buffer; + this->buffer = newBuffer; this->count += other->count; this->dimensionSizes[0] = this->count; } @@ -238,16 +238,22 @@ static QirArray::TItemCount RunCount(const QirArray::TDimContainer& dimensionSiz } /*============================================================================== - Implementation of quantum__rt__* methods for arrays + Implementation of __quantum__rt__* methods for arrays ==============================================================================*/ extern "C" { - QirArray* quantum__rt__qubit_allocate_array(int64_t count) // TODO: Use `QirArray::TItemCount count` - { // (breaking change). + QirArray* __quantum__rt__qubit_allocate_array(int64_t count) // TODO: Use `QirArray::TItemCount count` + { // (breaking change). return new QirArray((QirArray::TItemCount)count); } - void quantum__rt__qubit_release_array(QirArray* qa) + QirArray* __quantum__rt__qubit_borrow_array(int64_t count) + { + // Currently we implement borrowing as allocation. + return __quantum__rt__qubit_allocate_array(count); + } + + void __quantum__rt__qubit_release_array(QirArray* qa) { if (qa == nullptr) { @@ -260,23 +266,28 @@ extern "C" Qubit* qubits = reinterpret_cast(qa->buffer); for (QirArray::TItemCount i = 0; i < qa->count; i++) { - quantum__rt__qubit_release(qubits[i]); + __quantum__rt__qubit_release(qubits[i]); } } - quantum__rt__array_update_reference_count(qa, -1); + __quantum__rt__array_update_reference_count(qa, -1); + } + + void __quantum__rt__qubit_return_array(QirArray* qa) + { + // Currently we implement borrowing as allocation. + __quantum__rt__qubit_release_array(qa); } - // TODO: Use `QirArray::TItemSize itemSizeInBytes, QirArray::TItemCount count_items` (breaking change): - QirArray* quantum__rt__array_create_1d(int32_t itemSizeInBytes, int64_t count_items) + QirArray* __quantum__rt__array_create_1d(int32_t itemSizeInBytes, int64_t countItems) { assert(itemSizeInBytes > 0); - return new QirArray((QirArray::TItemCount)count_items, (QirArray::TItemSize)itemSizeInBytes); + return new QirArray((QirArray::TItemCount)countItems, (QirArray::TItemSize)itemSizeInBytes); } // Bucketing of addref/release is non-standard so for now we'll keep the more traditional addref/release semantics // in the native types. Should reconsider, if the perf of the loops becomes an issue. - void quantum__rt__array_update_reference_count(QirArray* array, int32_t increment) + void __quantum__rt__array_update_reference_count(QirArray* array, int32_t increment) { if (array == nullptr || increment == 0) { @@ -304,7 +315,7 @@ extern "C" } } - void quantum__rt__array_update_alias_count(QirArray* array, int32_t increment) + void __quantum__rt__array_update_alias_count(QirArray* array, int32_t increment) { if (array == nullptr || increment == 0) { @@ -313,26 +324,26 @@ extern "C" array->aliasCount += increment; if (array->aliasCount < 0) { - quantum__rt__fail(quantum__rt__string_create("Alias count cannot be negative!")); + __quantum__rt__fail(__quantum__rt__string_create("Alias count cannot be negative!")); } } // TODO: Use `QirArray::TItemCount index` (breaking change): - char* quantum__rt__array_get_element_ptr_1d(QirArray* array, int64_t index) + char* __quantum__rt__array_get_element_ptr_1d(QirArray* array, int64_t index) { assert(array != nullptr); return array->GetItemPointer((QirArray::TItemCount)index); } // Returns the number of dimensions in the array. - int32_t quantum__rt__array_get_dim(QirArray* array) // TODO: Return `QirArray::TDimCount` (breaking change). + int32_t __quantum__rt__array_get_dim(QirArray* array) // TODO: Return `QirArray::TDimCount` (breaking change). { assert(array != nullptr); return array->dimensions; } // TODO: Use `QirArray::TDimCount dim`, return `QirArray::TItemCount` (breaking change): - int64_t quantum__rt__array_get_size(QirArray* array, int32_t dim) + int64_t __quantum__rt__array_get_size(QirArray* array, int32_t dim) { assert(array != nullptr); assert(dim < array->dimensions); @@ -340,7 +351,12 @@ extern "C" return array->dimensionSizes[(size_t)dim]; } - QirArray* quantum__rt__array_copy(QirArray* array, bool forceNewInstance) + int64_t __quantum__rt__array_get_size_1d(QirArray* array) + { + return __quantum__rt__array_get_size(array, 0); + } + + QirArray* __quantum__rt__array_copy(QirArray* array, bool forceNewInstance) { if (array == nullptr) { @@ -354,7 +370,7 @@ extern "C" return array; } - QirArray* quantum__rt__array_concatenate(QirArray* head, QirArray* tail) + QirArray* __quantum__rt__array_concatenate(QirArray* head, QirArray* tail) { assert(head != nullptr && tail != nullptr); assert(head->dimensions == 1 && tail->dimensions == 1); @@ -368,7 +384,7 @@ extern "C" // The variable arguments should be a sequence of int64_ts contains the length of each dimension. The bytes of the // new array should be set to zero. // TODO: Use unsigned types (breaking change): - QirArray* quantum__rt__array_create_nonvariadic(int itemSizeInBytes, int countDimensions, va_list dims) + QirArray* __quantum__rt__array_create_nonvariadic(int itemSizeInBytes, int countDimensions, va_list dims) { QirArray::TDimContainer dimSizes; dimSizes.reserve((size_t)countDimensions); @@ -389,17 +405,17 @@ extern "C" std::move(dimSizes)); } - QirArray* quantum__rt__array_create(int itemSizeInBytes, int countDimensions, ...) // NOLINT + QirArray* __quantum__rt__array_create(int itemSizeInBytes, int countDimensions, ...) // NOLINT { va_list args; va_start(args, countDimensions); - QirArray* array = quantum__rt__array_create_nonvariadic(itemSizeInBytes, countDimensions, args); + QirArray* array = __quantum__rt__array_create_nonvariadic(itemSizeInBytes, countDimensions, args); va_end(args); return array; } - char* quantum__rt__array_get_element_ptr_nonvariadic(QirArray* array, va_list args) // NOLINT + char* __quantum__rt__array_get_element_ptr_nonvariadic(QirArray* array, va_list args) // NOLINT { assert(array != nullptr); @@ -421,13 +437,13 @@ extern "C" #pragma GCC diagnostic ignored "-Wvarargs" // Returns a pointer to the indicated element of the array. The variable arguments should be a sequence of int64_ts // that are the indices for each dimension. - char* quantum__rt__array_get_element_ptr(QirArray* array, ...) // NOLINT + char* __quantum__rt__array_get_element_ptr(QirArray* array, ...) // NOLINT { assert(array != nullptr); va_list args; va_start(args, array->dimensions); // TODO: (Bug or hack?) Replace `array->dimensions` with `array`. - char* ptr = quantum__rt__array_get_element_ptr_nonvariadic(array, args); + char* ptr = __quantum__rt__array_get_element_ptr_nonvariadic(array, args); va_end(args); return ptr; @@ -534,7 +550,7 @@ extern "C" // When range covers the whole dimension, can return a copy of the array without doing any math. if (range.step == 1 && range.start == 0 && range.end == array->dimensionSizes[(size_t)dim]) { - return quantum__rt__array_copy(array, true /*force*/); + return __quantum__rt__array_copy(array, true /*force*/); } // Create slice array of appropriate size. @@ -543,6 +559,10 @@ extern "C" const QirArray::TItemCount sliceItemsCount = std::accumulate( sliceDims.begin(), sliceDims.end(), (QirArray::TItemCount)1, std::multiplies()); QirArray* slice = new QirArray(sliceItemsCount, itemSizeInBytes, dimensions, std::move(sliceDims)); + if (nullptr == slice->buffer) + { + return slice; + } const QirArray::TItemCount singleIndexRunCount = RunCount(array->dimensionSizes, (QirArray::TDimCount)dim); const QirArray::TItemCount rowCount = singleIndexRunCount * array->dimensionSizes[(size_t)dim]; @@ -602,7 +622,7 @@ extern "C" // projection is on, and the int64_t specifies the specific index value to project. The returned Array* will have // one fewer dimension than the existing array. // TODO: Use `QirArray::TDimCount dim, QirArray::TItemCount index` (breaking change): - QirArray* quantum__rt__array_project(QirArray* array, int dim, int64_t index) // NOLINT + QirArray* __quantum__rt__array_project(QirArray* array, int dim, int64_t index) // NOLINT { assert(array != nullptr); assert(dim >= 0 && dim < array->dimensions); @@ -619,6 +639,10 @@ extern "C" const QirArray::TItemCount projectItemsCount = std::accumulate( projectDims.begin(), projectDims.end(), (QirArray::TItemCount)1, std::multiplies()); QirArray* project = new QirArray(projectItemsCount, itemSizeInBytes, dimensions - 1, std::move(projectDims)); + if (nullptr == project->buffer) + { + return project; + } const QirArray::TItemCount singleIndexRunCount = RunCount(array->dimensionSizes, (QirArray::TDimCount)dim); const QirArray::TItemCount rowCount = singleIndexRunCount * array->dimensionSizes[(size_t)dim]; @@ -626,6 +650,7 @@ extern "C" assert((QirArray::TBufSize)singleIndexRunCount * itemSizeInBytes < std::numeric_limits::max()); // Using `<` rather than `<=` to calm down the compiler on 32-bit arch. + const QirArray::TBufSize chunkSize = singleIndexRunCount * itemSizeInBytes; QirArray::TItemCount dst = 0; diff --git a/src/Qir/Runtime/lib/QIR/bridge-rt.ll b/src/Qir/Runtime/lib/QIR/bridge-rt.ll index 6bf2efe9cbd..d30f4e24a67 100644 --- a/src/Qir/Runtime/lib/QIR/bridge-rt.ll +++ b/src/Qir/Runtime/lib/QIR/bridge-rt.ll @@ -1,284 +1,20 @@ ; Copyright (c) Microsoft Corporation. ; Licensed under the MIT License. -;======================================================================================================================= -; QIR types -; %Array = type opaque -%Callable = type opaque -%Qubit = type opaque %Range = type { i64, i64, i64 } -%Result = type opaque %String = type opaque -%Tuple = type opaque -%Pauli = type i2 -;======================================================================================================================= -; Native types -; NB: there is no overloading at IR level, so a call/invoke will be made even -; if the definition of the function mismatches the declaration of the arguments. -; It means we could declare here the bridge's C-functions using QIR types -; and avoid bitcasts. However, it seems prudent to be more explicit about -; what's going on and declare the true signatures, as generated by Clang. -; -%class.QUBIT = type opaque -%class.RESULT = type opaque %"struct.QirArray" = type opaque -%"struct.QirCallable" = type opaque %"struct.QirRange" = type { i64, i64, i64 } %"struct.QirString" = type opaque -%PauliId = type i32 -; %Tuple* is mapped to i8* -;======================================================================================================================= -; declarations of the native APIs the bridge redirects to -;======================================================================================================================= - -;------------------------------------------------------------------------------ -; classical -; -declare i8* @quantum__rt__memory_allocate(i64) -declare void @quantum__rt__fail(%"struct.QirString"*) - -;------------------------------------------------------------------------------ -; methods that delegate to the simulators -; -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 -; -declare %"struct.QirArray"* @quantum__rt__qubit_allocate_array(i64) -declare void @quantum__rt__qubit_release_array(%"struct.QirArray"*) -declare %"struct.QirArray"* @quantum__rt__array_copy(%"struct.QirArray"*, i1) -declare %"struct.QirArray"* @quantum__rt__array_concatenate(%"struct.QirArray"*, %"struct.QirArray"*) -declare %"struct.QirArray"* @quantum__rt__array_create_1d(i32, i64) -declare %"struct.QirArray"* @quantum__rt__array_create_nonvariadic(i32, i32, i8*) -declare i32 @quantum__rt__array_get_dim(%"struct.QirArray"*) -declare i8* @quantum__rt__array_get_element_ptr_1d(%"struct.QirArray"*, i64) -declare i8* @quantum__rt__array_get_element_ptr_nonvariadic(%Array*, i8*) -declare i64 @quantum__rt__array_get_size(%"struct.QirArray"*, i32) -declare %"struct.QirArray"* @quantum__rt__array_project(%"struct.QirArray"*, i32, i64) declare %"struct.QirArray"* @quantum__rt__array_slice(%"struct.QirArray"*, i32, %"struct.QirRange"* dereferenceable(24)) -declare void @quantum__rt__array_update_reference_count(%"struct.QirArray"*, i32) -declare void @quantum__rt__array_update_alias_count(%"struct.QirArray"*, i32) - -; needed for the variadic array functions -declare void @llvm.va_start(i8*) -declare void @llvm.va_end(i8*) - -;------------------------------------------------------------------------------ -; tuples and callables -; -declare i8* @quantum__rt__tuple_create(i64) -declare void @quantum__rt__tuple_update_reference_count(i8*, i32) -declare void @quantum__rt__tuple_update_alias_count(i8*, i32) -declare i8* @quantum__rt__tuple_copy(i8*, i1) - -declare void @quantum__rt__callable_update_reference_count(%"struct.QirCallable"*, i32) -declare %"struct.QirCallable"* @quantum__rt__callable_create(void (i8*, i8*, i8*)**, void (i8*, i64)**, i8*) -declare void @quantum__rt__callable_invoke(%"struct.QirCallable"*, i8*, i8*) -declare %"struct.QirCallable"* @quantum__rt__callable_copy(%"struct.QirCallable"*, i1) -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"*, i32) - -;------------------------------------------------------------------------------ -; strings -; -declare %"struct.QirString"* @quantum__rt__string_create(i8*) -declare void @quantum__rt__string_update_reference_count(%"struct.QirString"*, i32) -declare %"struct.QirString"* @quantum__rt__string_concatenate(%"struct.QirString"*, %"struct.QirString"*) -declare i1 @quantum__rt__string_equal(%"struct.QirString"*, %"struct.QirString"*) -declare %"struct.QirString"* @quantum__rt__int_to_string(i64) -declare %"struct.QirString"* @quantum__rt__double_to_string(double) -declare %"struct.QirString"* @quantum__rt__bool_to_string(i1) -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 -;======================================================================================================================= - -;------------------------------------------------------------------------------ -; classical bridge -; - -; 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 -; -; NYI: -;define dllexport %Qubit* @__quantum__rt__qubit_borrow() -;define dllexport void @__quantum__rt__qubit_return(%Qubit*) -;define dllexport %Array* @__quantum__rt__qubit_borrow_array(i64) -;define dllexport void @__quantum__rt__qubit_return_array(%Array*) -; -define dllexport %Qubit* @__quantum__rt__qubit_allocate() { - %q = call %class.QUBIT* @quantum__rt__qubit_allocate() - %.q = bitcast %class.QUBIT* %q to %Qubit* - ret %Qubit* %.q -} - -define dllexport void @__quantum__rt__qubit_release(%Qubit* %.q) { - %q = bitcast %Qubit* %.q to %class.QUBIT* - call void @quantum__rt__qubit_release(%class.QUBIT* %q) - ret void -} - -define dllexport %Array* @__quantum__rt__qubit_allocate_array(i64 %n) { - %qa = call %"struct.QirArray"* @quantum__rt__qubit_allocate_array(i64 %n) - %.qa = bitcast %"struct.QirArray"* %qa to %Array* - ret %Array* %.qa -} - -define dllexport void @__quantum__rt__qubit_release_array(%Array* %.qa) { - %qa = bitcast %Array* %.qa to %"struct.QirArray"* - call void @quantum__rt__qubit_release_array(%"struct.QirArray"* %qa) - ret void -} - - -;------------------------------------------------------------------------------ -; results bridge -; -define dllexport i1 @__quantum__rt__result_equal(%Result* %.r1, %Result* %.r2) { - %r1 = bitcast %Result* %.r1 to %class.RESULT* - %r2 = bitcast %Result* %.r2 to %class.RESULT* - %c = call i1 @quantum__rt__result_equal(%class.RESULT* %r1, %class.RESULT* %r2) - ret i1 %c -} - -define dllexport void @__quantum__rt__result_update_reference_count(%Result* %.r, i32 %c) { - %r = bitcast %Result* %.r to %class.RESULT* - 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 -; -define dllexport %Array* @__quantum__rt__array_concatenate(%Array* %.head, %Array* %.tail) { - %head = bitcast %Array* %.head to %"struct.QirArray"* - %tail = bitcast %Array* %.tail to %"struct.QirArray"* - %con = call %"struct.QirArray"* @quantum__rt__array_concatenate(%"struct.QirArray"* %head, %"struct.QirArray"* %tail) - %.con = bitcast %"struct.QirArray"* %con to %Array* - ret %Array* %.con -} - -define dllexport %Array* @__quantum__rt__array_copy(%Array* %.ar, i1 %force) { - %ar = bitcast %Array* %.ar to %"struct.QirArray"* - %ar_copy = call %"struct.QirArray"* @quantum__rt__array_copy(%"struct.QirArray"* %ar, i1 %force) - %.ar_copy = bitcast %"struct.QirArray"* %ar_copy to %Array* - ret %Array* %.ar_copy -} - -; TODO: This bridge isn't cross-platform! -; it works on Windows but on Linux %args ends up not being a valid pointer. -define dllexport %Array* @__quantum__rt__array_create(i32 %item_size, i32 %dim_count, ...) { - %args1 = alloca i8*, align 8 - %args2 = bitcast i8** %args1 to i8* - call void @llvm.va_start(i8* %args2) - %args = load i8*, i8** %args1, align 8 - %ar = call %"struct.QirArray"* @quantum__rt__array_create_nonvariadic(i32 %item_size, i32 %dim_count, i8* %args) - call void @llvm.va_end(i8* %args2) - %.ar = bitcast %"struct.QirArray"* %ar to %Array* - ret %Array* %.ar -} - -define dllexport %Array* @__quantum__rt__array_create_1d(i32 %item_size, i64 %count) { - %ar = call %"struct.QirArray"* @quantum__rt__array_create_1d(i32 %item_size, i64 %count) - %.ar = bitcast %"struct.QirArray"* %ar to %Array* - ret %Array* %.ar -} - -define dllexport i32 @__quantum__rt__array_get_dim(%Array* %.ar) { - %ar = bitcast %Array* %.ar to %"struct.QirArray"* - %dim_count = call i32 @quantum__rt__array_get_dim(%"struct.QirArray"* %ar) - ret i32 %dim_count -} - -define dllexport i8* @__quantum__rt__array_get_element_ptr(%Array* %.ar, ...) { - %args1 = alloca i8*, align 8 - %args2 = bitcast i8** %args1 to i8* - call void @llvm.va_start(i8* %args2) - %args = load i8*, i8** %args1, align 8 - %ptr = call i8* @quantum__rt__array_get_element_ptr_nonvariadic(%Array* %.ar, i8* %args) - call void @llvm.va_end(i8* %args2) - ret i8* %ptr -} - -define dllexport i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %.ar, i64 %i) { - %ar = bitcast %Array* %.ar to %"struct.QirArray"* - %item = - call i8* @quantum__rt__array_get_element_ptr_1d(%"struct.QirArray"* %ar, i64 %i) - ret i8* %item -} - -define dllexport i64 @__quantum__rt__array_get_size(%Array* %.ar, i32 %dim) { - %ar = bitcast %Array* %.ar to %"struct.QirArray"* - %l = call i64 @quantum__rt__array_get_size(%"struct.QirArray"* %ar, i32 %dim) - ret i64 %l -} - -define dllexport i64 @__quantum__rt__array_get_size_1d(%Array* %.ar) { - %l = call i64 @__quantum__rt__array_get_size(%Array* %.ar, i32 0) - ret i64 %l -} - -define dllexport %Array* @__quantum__rt__array_project(%Array* %.ar, i32 %dim, i64 %index) { - %ar = bitcast %Array* %.ar to %"struct.QirArray"* - %project = call %"struct.QirArray"* @quantum__rt__array_project(%"struct.QirArray"* %ar, i32 %dim, i64 %index) - %.project = bitcast %"struct.QirArray"* %project to %Array* - ret %Array* %.project -} +; NOTE: These three functions can be converted to extern C once the spec and compiler are updated to pass %Range by +; pointer instead of by value (see https://github.com/microsoft/qsharp-language/issues/108). Once that +; happens, this file can be removed. define dllexport %Array* @__quantum__rt__array_slice(%Array* %.ar, i32 %dim, %Range %.range) { %ar = bitcast %Array* %.ar to %"struct.QirArray"* @@ -296,186 +32,6 @@ 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, i32 %c) { - %ar = bitcast %Array* %.ar to %"struct.QirArray"* - 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, i32 %c) { - %ar = bitcast %Array* %.ar to %"struct.QirArray"* - call void @quantum__rt__array_update_alias_count(%"struct.QirArray"* %ar, i32 %c) - ret void -} - -;------------------------------------------------------------------------------ -; tuples bridge -; -define dllexport %Tuple* @__quantum__rt__tuple_create(i64 %size) { - %th = call i8* @quantum__rt__tuple_create(i64 %size) - %.th = bitcast i8* %th to %Tuple* - ret %Tuple* %.th -} - -define dllexport void @__quantum__rt__tuple_update_reference_count(%Tuple* %.th, i32 %c) { - %th = bitcast %Tuple* %.th to i8* - 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, i32 %c) { - %th = bitcast %Tuple* %.th to i8* - call void @quantum__rt__tuple_update_alias_count(i8* %th, i32 %c) - ret void -} - -define dllexport %Tuple* @__quantum__rt__tuple_copy(%Tuple* %.th, i1 %force) { - %th = bitcast %Tuple* %.th to i8* - %th2 = call i8* @quantum__rt__tuple_copy(i8* %th, i1 %force) - %.th2 = bitcast i8* %th2 to %Tuple* - ret %Tuple* %.th2 -} - -;------------------------------------------------------------------------------ -; callables bridge -; -define dllexport void @__quantum__rt__callable_update_reference_count(%Callable* %.clb, i32 %c) { - %clb = bitcast %Callable* %.clb to %"struct.QirCallable"* - 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, i32 %c) { - %clb = bitcast %Callable* %.clb to %"struct.QirCallable"* - call void @quantum__rt__callable_update_alias_count(%"struct.QirCallable"* %clb, i32 %c) - ret void -} - -define dllexport %Callable* @__quantum__rt__callable_create( - [4 x void (%Tuple*, %Tuple*, %Tuple*)*]* %.ft, [2 x void (%Tuple*, i64)*]* %.callbacks, %Tuple* %.capture) { - %ft = bitcast [4 x void (%Tuple*, %Tuple*, %Tuple*)*]* %.ft to void (i8*, i8*, i8*)** - %callbacks = bitcast [2 x void (%Tuple*, i64)*]* %.callbacks to void (i8*, i64)** - %capture = bitcast %Tuple* %.capture to i8* - %clb = call %"struct.QirCallable"* - @quantum__rt__callable_create(void (i8*, i8*, i8*)** %ft, void (i8*, i64)** %callbacks, i8* %capture) - %.clb = bitcast %"struct.QirCallable"* %clb to %Callable* - ret %Callable* %.clb -} - -define dllexport void @__quantum__rt__callable_invoke(%Callable* %.clb, %Tuple* %.args, %Tuple* %.res) { - %clb = bitcast %Callable* %.clb to %"struct.QirCallable"* - %args = bitcast %Tuple* %.args to i8* - %res = bitcast %Tuple* %.res to i8* - call void @quantum__rt__callable_invoke(%"struct.QirCallable"* %clb, i8* %args, i8* %res) - ret void -} - -define dllexport %Callable* @__quantum__rt__callable_copy(%Callable* %.clb, i1 %force) { - %clb = bitcast %Callable* %.clb to %"struct.QirCallable"* - %clb_copy = call %"struct.QirCallable"* @quantum__rt__callable_copy(%"struct.QirCallable"* %clb, i1 %force) - %.clb_copy = bitcast %"struct.QirCallable"* %clb_copy to %Callable* - ret %Callable* %.clb_copy -} - -define dllexport %Callable* @__quantum__rt__callable_make_adjoint(%Callable* %.clb) { - %clb = bitcast %Callable* %.clb to %"struct.QirCallable"* - %clb_adj = call %"struct.QirCallable"* @quantum__rt__callable_make_adjoint(%"struct.QirCallable"* %clb) - %.clb_adj = bitcast %"struct.QirCallable"* %clb_adj to %Callable* - ret %Callable* %.clb_adj -} - -define dllexport %Callable* @__quantum__rt__callable_make_controlled(%Callable* %.clb) { - %clb = bitcast %Callable* %.clb to %"struct.QirCallable"* - %clb_cnt = call %"struct.QirCallable"* @quantum__rt__callable_make_controlled(%"struct.QirCallable"* %clb) - %.clb_cnt = bitcast %"struct.QirCallable"* %clb_cnt to %Callable* - ret %Callable* %.clb_cnt -} - -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 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(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, i32 %c) { - %str = bitcast %String* %.str to %"struct.QirString"* - call void @quantum__rt__string_update_reference_count(%"struct.QirString"* %str, i32 %c) - ret void -} - -define dllexport %String* @__quantum__rt__string_concatenate(%String* %.head, %String* %.tail) { - %head = bitcast %String* %.head to %"struct.QirString"* - %tail = bitcast %String* %.tail to %"struct.QirString"* - %str = call %"struct.QirString"* @quantum__rt__string_concatenate( - %"struct.QirString"* %head, %"struct.QirString"* %tail) - %.str = bitcast %"struct.QirString"* %str to %String* - ret %String* %.str -} - -define dllexport i1 @__quantum__rt__string_equal(%String* %.str1, %String* %.str2) { - %str1 = bitcast %String* %.str1 to %"struct.QirString"* - %str2 = bitcast %String* %.str2 to %"struct.QirString"* - %eq = call i1 @quantum__rt__string_equal(%"struct.QirString"* %str1, %"struct.QirString"* %str2) - ret i1 %eq -} - -define dllexport %String* @__quantum__rt__int_to_string(i64 %val) { - %str = call %"struct.QirString"* @quantum__rt__int_to_string(i64 %val) - %.str = bitcast %"struct.QirString"* %str to %String* - ret %String* %.str -} - -define dllexport %String* @__quantum__rt__double_to_string(double %val) { - %str = call %"struct.QirString"* @quantum__rt__double_to_string(double %val) - %.str = bitcast %"struct.QirString"* %str to %String* - ret %String* %.str -} - -define dllexport %String* @__quantum__rt__bool_to_string(i1 %val) { - %str = call %"struct.QirString"* @quantum__rt__bool_to_string(i1 %val) - %.str = bitcast %"struct.QirString"* %str to %String* - ret %String* %.str -} - -define dllexport %String* @__quantum__rt__result_to_string(%Result* %.r) { - %r = bitcast %Result* %.r to %"class.RESULT"* - %str = call %"struct.QirString"* @quantum__rt__result_to_string(%"class.RESULT"* %r) - %.str = bitcast %"struct.QirString"* %str to %String* - ret %String* %.str -} - -define dllexport %String* @__quantum__rt__pauli_to_string(%Pauli %.pauli) { - %pauli = zext %Pauli %.pauli to %PauliId - %str = call %"struct.QirString"* @quantum__rt__pauli_to_string(%PauliId %pauli) - %.str = bitcast %"struct.QirString"* %str to %String* - ret %String* %.str -} - -define dllexport %String* @__quantum__rt__qubit_to_string(%Qubit* %.q) { - %q = bitcast %Qubit* %.q to %"class.QUBIT"* - %str = call %"struct.QirString"* @quantum__rt__qubit_to_string(%"class.QUBIT"* %q) - %.str = bitcast %"struct.QirString"* %str to %String* - ret %String* %.str -} - define dllexport %String* @__quantum__rt__range_to_string(%Range %.range) { %.prange = alloca %Range store %Range %.range, %Range* %.prange @@ -483,43 +39,4 @@ define dllexport %String* @__quantum__rt__range_to_string(%Range %.range) { %str = call %"struct.QirString"* @quantum__rt__range_to_string(%"struct.QirRange"* dereferenceable(24) %range) %.str = bitcast %"struct.QirString"* %str to %String* 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*, 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*) -;define dllexport %BigInt* @__quantum__rt__bigint_multiply(%BigInt*, %BigInt*) -;define dllexport %BigInt* @__quantum__rt__bigint_divide(%BigInt*, %BigInt*) -;define dllexport %BigInt* @__quantum__rt__bigint_modulus(%BigInt*, %BigInt*) -;define dllexport %BigInt* @__quantum__rt__bigint_power(%BigInt*, i32) -;define dllexport %BigInt* @__quantum__rt__bigint_bitand(%BigInt*, %BigInt*) -;define dllexport %BigInt* @__quantum__rt__bigint_bitor(%BigInt*, %BigInt*) -;define dllexport %BigInt* @__quantum__rt__bigint_bitxor(%BigInt*, %BigInt*) -;define dllexport %BigInt* @__quantum__rt__bigint_bitnot(%BigInt*) -;define dllexport %BigInt* @__quantum__rt__bigint_shiftleft(%BigInt*, i64) -;define dllexport %BigInt* @__quantum__rt__bigint_shiftright(%BigInt*, i64) -;define dllexport i1 @__quantum__rt__bigint_equal(%BigInt*, %BigInt*) -;define dllexport i1 @__quantum__rt__bigint_greater(%BigInt*, %BigInt*) -;define dllexport i1 @__quantum__rt__bigint_greater_eq(%BigInt*, %BigInt*) -; \ No newline at end of file +} \ No newline at end of file diff --git a/src/Qir/Runtime/lib/QIR/callables.cpp b/src/Qir/Runtime/lib/QIR/callables.cpp index 357ca74b01c..93cd1dee466 100644 --- a/src/Qir/Runtime/lib/QIR/callables.cpp +++ b/src/Qir/Runtime/lib/QIR/callables.cpp @@ -18,18 +18,18 @@ QirTupleHeader* FlattenControlArrays(QirTupleHeader* tuple, int depth); using namespace Microsoft::Quantum; /*============================================================================== - Implementation of quantum__rt__tuple_* and quantum__rt__callable_* + Implementation of __quantum__rt__tuple_* and __quantum__rt__callable_* ==============================================================================*/ extern "C" { - PTuple quantum__rt__tuple_create(int64_t size) // TODO: Use unsigned integer type for param (breaking change). + PTuple __quantum__rt__tuple_create(int64_t size) // TODO: Use unsigned integer type for param (breaking change). { assert((uint64_t)size < std::numeric_limits::max()); // Using `<` rather than `<=` to calm down the compiler on 64-bit arch. return QirTupleHeader::Create(static_cast(size))->AsTuple(); } - void quantum__rt__tuple_update_reference_count(PTuple tuple, int32_t increment) + void __quantum__rt__tuple_update_reference_count(PTuple tuple, int32_t increment) { if (tuple == nullptr || increment == 0) { @@ -53,7 +53,7 @@ extern "C" } } - void quantum__rt__tuple_update_alias_count(PTuple tuple, int32_t increment) + void __quantum__rt__tuple_update_alias_count(PTuple tuple, int32_t increment) { if (tuple == nullptr || increment == 0) { @@ -64,11 +64,11 @@ extern "C" if (th->aliasCount < 0) { - quantum__rt__fail(quantum__rt__string_create("Alias count cannot be negative")); + __quantum__rt__fail(__quantum__rt__string_create("Alias count cannot be negative")); } } - PTuple quantum__rt__tuple_copy(PTuple tuple, bool forceNewInstance) + PTuple __quantum__rt__tuple_copy(PTuple tuple, bool forceNewInstance) { if (tuple == nullptr) { @@ -85,7 +85,7 @@ extern "C" return tuple; } - void quantum__rt__callable_update_reference_count(QirCallable* callable, int32_t increment) + void __quantum__rt__callable_update_reference_count(QirCallable* callable, int32_t increment) { if (callable == nullptr || increment == 0) { @@ -102,12 +102,16 @@ extern "C" { for (int i = increment; i < 0; i++) { - (void)callable->Release(); + if (0 == callable->Release()) + { + assert(-1 == i && "Attempting to decrement reference count below zero!"); + break; + } } } } - void quantum__rt__callable_update_alias_count(QirCallable* callable, int32_t increment) + void __quantum__rt__callable_update_alias_count(QirCallable* callable, int32_t increment) { if (callable == nullptr || increment == 0) { @@ -116,20 +120,20 @@ extern "C" callable->UpdateAliasCount(increment); } - QirCallable* quantum__rt__callable_create(t_CallableEntry* entries, t_CaptureCallback* captureCallbacks, - PTuple capture) + QirCallable* __quantum__rt__callable_create(t_CallableEntry* entries, t_CaptureCallback* captureCallbacks, + PTuple capture) { assert(entries != nullptr); return new QirCallable(entries, captureCallbacks, capture); } - void quantum__rt__callable_invoke(QirCallable* callable, PTuple args, PTuple result) + void __quantum__rt__callable_invoke(QirCallable* callable, PTuple args, PTuple result) { assert(callable != nullptr); callable->Invoke(args, result); } - QirCallable* quantum__rt__callable_copy(QirCallable* other, bool forceNewInstance) + QirCallable* __quantum__rt__callable_copy(QirCallable* other, bool forceNewInstance) { if (other == nullptr) { @@ -142,21 +146,26 @@ extern "C" return other->CloneIfShared(); } - void quantum__rt__callable_make_adjoint(QirCallable* callable) + void __quantum__rt__callable_make_adjoint(QirCallable* callable) { assert(callable != nullptr); callable->ApplyFunctor(QirCallable::Adjoint); } - void quantum__rt__callable_make_controlled(QirCallable* callable) + void __quantum__rt__callable_make_controlled(QirCallable* callable) { assert(callable != nullptr); callable->ApplyFunctor(QirCallable::Controlled); } - void quantum__rt__callable_memory_management(int32_t index, QirCallable* callable, int32_t parameter) + void __quantum__rt__capture_update_reference_count(QirCallable* callable, int32_t parameter) { - callable->InvokeCaptureCallback(index, parameter); + callable->InvokeCaptureCallback(0, parameter); + } + + void __quantum__rt__capture_update_alias_count(QirCallable* callable, int32_t parameter) + { + callable->InvokeCaptureCallback(1, parameter); } } @@ -318,7 +327,7 @@ void QirCallable::UpdateAliasCount(int increment) this->aliasCount += increment; if (this->aliasCount < 0) { - quantum__rt__fail(quantum__rt__string_create("Alias count cannot be negative")); + __quantum__rt__fail(__quantum__rt__string_create("Alias count cannot be negative")); } } @@ -409,7 +418,7 @@ void QirCallable::Invoke(PTuple args, PTuple result) this->functionTable[this->appliedFunctor](capture, flat->AsTuple(), result); QirArray* controls = *reinterpret_cast(flat->AsTuple()); - quantum__rt__array_update_reference_count(controls, -1); + __quantum__rt__array_update_reference_count(controls, -1); flat->Release(); } } @@ -417,9 +426,9 @@ void QirCallable::Invoke(PTuple args, PTuple result) void QirCallable::Invoke() { assert((this->appliedFunctor & QirCallable::Controlled) == 0 && "Cannot invoke controlled callable without args"); - PTuple args = quantum__rt__tuple_create(0); + PTuple args = __quantum__rt__tuple_create(0); this->Invoke(args, nullptr); - quantum__rt__tuple_update_reference_count(args, -1); + __quantum__rt__tuple_update_reference_count(args, -1); } // A + A = I; A + C = C + A = CA; C + C = C; CA + A = C; CA + C = CA @@ -433,7 +442,7 @@ void QirCallable::ApplyFunctor(int functor) if (this->functionTable[this->appliedFunctor] == nullptr) { this->appliedFunctor ^= QirCallable::Adjoint; - quantum__rt__fail(quantum__rt__string_create("The callable doesn't provide adjoint operation")); + __quantum__rt__fail(__quantum__rt__string_create("The callable doesn't provide adjoint operation")); } } else if (functor == QirCallable::Controlled) @@ -445,7 +454,7 @@ void QirCallable::ApplyFunctor(int functor) { this->appliedFunctor ^= QirCallable::Controlled; } - quantum__rt__fail(quantum__rt__string_create("The callable doesn't provide controlled operation")); + __quantum__rt__fail(__quantum__rt__string_create("The callable doesn't provide controlled operation")); } this->controlledDepth++; } diff --git a/src/Qir/Runtime/lib/QIR/delegated.cpp b/src/Qir/Runtime/lib/QIR/delegated.cpp index 5ebb20a41da..9100a2d1cb7 100644 --- a/src/Qir/Runtime/lib/QIR/delegated.cpp +++ b/src/Qir/Runtime/lib/QIR/delegated.cpp @@ -25,28 +25,62 @@ static std::unordered_map& AllocatedResults() return allocatedResults; } +static Microsoft::Quantum::IRestrictedAreaManagement* RestrictedAreaManagement() +{ + return dynamic_cast( + Microsoft::Quantum::GlobalContext()->GetDriver()); +} + extern "C" { - Result quantum__rt__result_get_zero() + Result __quantum__rt__result_get_zero() { return Microsoft::Quantum::GlobalContext()->GetDriver()->UseZero(); } - Result quantum__rt__result_get_one() + + Result __quantum__rt__result_get_one() { return Microsoft::Quantum::GlobalContext()->GetDriver()->UseOne(); } - QUBIT* quantum__rt__qubit_allocate() // NOLINT + QUBIT* __quantum__rt__qubit_allocate() { return Microsoft::Quantum::GlobalContext()->GetDriver()->AllocateQubit(); } - void quantum__rt__qubit_release(QUBIT* qubit) // NOLINT + void __quantum__rt__qubit_release(QUBIT* qubit) { Microsoft::Quantum::GlobalContext()->GetDriver()->ReleaseQubit(qubit); } - void quantum__rt__result_update_reference_count(RESULT* r, int32_t increment) + QUBIT* __quantum__rt__qubit_borrow() + { + // Currently we implement borrowing as allocation. + return __quantum__rt__qubit_allocate(); + } + + void __quantum__rt__qubit_return(QUBIT* qubit) + { + // Currently we implement borrowing as allocation. + __quantum__rt__qubit_release(qubit); + } + + void __quantum__rt__qubit_restricted_reuse_area_start() + { + RestrictedAreaManagement()->StartArea(); + } + + void __quantum__rt__qubit_restricted_reuse_segment_next() + { + RestrictedAreaManagement()->NextSegment(); + } + + void __quantum__rt__qubit_restricted_reuse_area_end() + { + RestrictedAreaManagement()->EndArea(); + } + + void __quantum__rt__result_update_reference_count(RESULT* r, int32_t increment) { if (increment == 0) { @@ -94,7 +128,7 @@ extern "C" } } - bool quantum__rt__result_equal(RESULT* r1, RESULT* r2) // NOLINT + bool __quantum__rt__result_equal(RESULT* r1, RESULT* r2) // NOLINT { if (r1 == r2) { @@ -104,18 +138,18 @@ extern "C" } // Returns a string representation of the result. - QirString* quantum__rt__result_to_string(RESULT* result) // NOLINT + QirString* __quantum__rt__result_to_string(RESULT* result) // NOLINT { ResultValue rv = Microsoft::Quantum::GlobalContext()->GetDriver()->GetResultValue(result); assert(rv != Result_Pending); - return (rv == Result_Zero) ? quantum__rt__string_create("Zero") : quantum__rt__string_create("One"); + return (rv == Result_Zero) ? __quantum__rt__string_create("Zero") : __quantum__rt__string_create("One"); } // Returns a string representation of the qubit. - QirString* quantum__rt__qubit_to_string(QUBIT* qubit) // NOLINT + QirString* __quantum__rt__qubit_to_string(QUBIT* qubit) // NOLINT { - return quantum__rt__string_create( + return __quantum__rt__string_create( Microsoft::Quantum::GlobalContext()->GetDriver()->QubitToString(qubit).c_str()); } } diff --git a/src/Qir/Runtime/lib/QIR/strings.cpp b/src/Qir/Runtime/lib/QIR/strings.cpp index e384aeae616..7fc034bce7c 100644 --- a/src/Qir/Runtime/lib/QIR/strings.cpp +++ b/src/Qir/Runtime/lib/QIR/strings.cpp @@ -28,7 +28,7 @@ static QirString* CreateOrReuseAlreadyAllocated(std::string&& str) if (alreadyAllocated != AllocatedStrings().end()) { qstr = alreadyAllocated->second; - assert(qstr->str.compare(str) == 0); + assert(qstr->str == str); qstr->refCount++; } else @@ -57,12 +57,12 @@ QirString::QirString(const char* cstr) extern "C" { // Creates a string from an array of UTF-8 bytes. - QirString* quantum__rt__string_create(const char* bytes) // NOLINT + QirString* __quantum__rt__string_create(const char* bytes) // NOLINT { return CreateOrReuseAlreadyAllocated(std::string(bytes)); } - void quantum__rt__string_update_reference_count(QirString* qstr, int32_t increment) // NOLINT + void __quantum__rt__string_update_reference_count(QirString* qstr, int32_t increment) // NOLINT { if (qstr == nullptr || increment == 0) { @@ -74,7 +74,7 @@ extern "C" if (qstr->refCount < 0) { - quantum__rt__fail(quantum__rt__string_create("Attempting to decrement reference count below zero!")); + __quantum__rt__fail(__quantum__rt__string_create("Attempting to decrement reference count below zero!")); } else if (qstr->refCount == 0) { @@ -87,26 +87,26 @@ extern "C" } // Creates a new string that is the concatenation of the two argument strings. - QirString* quantum__rt__string_concatenate(QirString* left, QirString* right) // NOLINT + QirString* __quantum__rt__string_concatenate(QirString* left, QirString* right) // NOLINT { return CreateOrReuseAlreadyAllocated(left->str + right->str); } // Returns true if the two strings are equal, false otherwise. - bool quantum__rt__string_equal(QirString* left, QirString* right) // NOLINT + bool __quantum__rt__string_equal(QirString* left, QirString* right) // NOLINT { - assert((left == right) == (left->str.compare(right->str) == 0)); + assert((left == right) == (left->str == right->str)); return left == right; } // Returns a string representation of the integer. - QirString* quantum__rt__int_to_string(int64_t value) // NOLINT + QirString* __quantum__rt__int_to_string(int64_t value) // NOLINT { return CreateOrReuseAlreadyAllocated(std::to_string(value)); } // Returns a string representation of the double. - QirString* quantum__rt__double_to_string(double value) // NOLINT + QirString* __quantum__rt__double_to_string(double value) // NOLINT { std::ostringstream oss; oss.precision(std::numeric_limits::max_digits10); @@ -115,7 +115,7 @@ extern "C" // Remove padding zeros from the decimal part (relies on the fact that the output for integers always contains // period). - std::size_t pos1 = str.find_last_not_of("0"); + std::size_t pos1 = str.find_last_not_of('0'); if (pos1 != std::string::npos) { str.erase(pos1 + 1); @@ -130,29 +130,29 @@ extern "C" } // Returns a string representation of the Boolean. - QirString* quantum__rt__bool_to_string(bool value) // NOLINT + QirString* __quantum__rt__bool_to_string(bool value) // NOLINT { std::string str = value ? "true" : "false"; return CreateOrReuseAlreadyAllocated(std::move(str)); } // Returns a string representation of the Pauli. - QirString* quantum__rt__pauli_to_string(PauliId pauli) // NOLINT + QirString* __quantum__rt__pauli_to_string(PauliId pauli) // NOLINT { switch (pauli) { case PauliId_I: - return quantum__rt__string_create("PauliI"); + return __quantum__rt__string_create("PauliI"); case PauliId_X: - return quantum__rt__string_create("PauliX"); + return __quantum__rt__string_create("PauliX"); case PauliId_Y: - return quantum__rt__string_create("PauliY"); + return __quantum__rt__string_create("PauliY"); case PauliId_Z: - return quantum__rt__string_create("PauliZ"); + return __quantum__rt__string_create("PauliZ"); default: break; } - return quantum__rt__string_create(""); + return __quantum__rt__string_create(""); } // Returns a string representation of the range. @@ -166,22 +166,22 @@ extern "C" } oss << range.end; - return quantum__rt__string_create(oss.str().c_str()); + return __quantum__rt__string_create(oss.str().c_str()); } - const char* quantum__rt__string_get_data(QirString* str) // NOLINT + 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 + uint32_t __quantum__rt__string_get_length(QirString* str) // NOLINT { return (uint32_t)(str->str.size()); } // Implemented in delegated.cpp: - // QirString* quantum__rt__qubit_to_string(QUBIT* qubit); // NOLINT + // QirString* __quantum__rt__qubit_to_string(QUBIT* qubit); // NOLINT // Returns a string representation of the big integer. - // TODO QirString* quantum__rt__bigint_to_string(QirBigInt*); // NOLINT + // TODO QirString* __quantum__rt__bigint_to_string(QirBigInt*); // NOLINT } diff --git a/src/Qir/Runtime/lib/QIR/utils.cpp b/src/Qir/Runtime/lib/QIR/utils.cpp index d663bcb333a..82b18700108 100644 --- a/src/Qir/Runtime/lib/QIR/utils.cpp +++ b/src/Qir/Runtime/lib/QIR/utils.cpp @@ -16,18 +16,18 @@ extern "C" { - char* quantum__rt__memory_allocate(uint64_t size) + 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 + void __quantum__rt__fail(QirString* msg) // NOLINT { - quantum__rt__fail_cstr(msg->str.c_str()); + __quantum__rt__fail_cstr(msg->str.c_str()); } - void quantum__rt__fail_cstr(const char* cstr) + void __quantum__rt__fail_cstr(const char* cstr) { Microsoft::Quantum::OutputStream::Get() << cstr << std::endl; Microsoft::Quantum::OutputStream::Get().flush(); diff --git a/src/Qir/Runtime/lib/QSharpCore/.clang-tidy b/src/Qir/Runtime/lib/QSharpCore/.clang-tidy deleted file mode 100644 index 8268b75c21d..00000000000 --- a/src/Qir/Runtime/lib/QSharpCore/.clang-tidy +++ /dev/null @@ -1 +0,0 @@ -Checks: '-*,bugprone-*' \ No newline at end of file diff --git a/src/Qir/Runtime/lib/QSharpCore/CMakeLists.txt b/src/Qir/Runtime/lib/QSharpCore/CMakeLists.txt index abf35258ede..d3fe9170f9f 100644 --- a/src/Qir/Runtime/lib/QSharpCore/CMakeLists.txt +++ b/src/Qir/Runtime/lib/QSharpCore/CMakeLists.txt @@ -12,7 +12,6 @@ set(qsharp_core_sup_source_files # 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(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) diff --git a/src/Qir/Runtime/lib/QSharpCore/README.md b/src/Qir/Runtime/lib/QSharpCore/README.md index c996c196249..1a80606d70a 100644 --- a/src/Qir/Runtime/lib/QSharpCore/README.md +++ b/src/Qir/Runtime/lib/QSharpCore/README.md @@ -18,16 +18,9 @@ Same-level entities are independent of each other (unless specified otherwise). ## Level 1 -**qsharp__core__qis.hpp** Declares `quantum__qis__*()` gate set implementations. +**qsharp__core__qis.hpp** Declares `__quantum__qis__*()` gate set implementations. Depends on `public\CoreTypes.hpp` (QUBIT, PauliId, RESULT) Uses `QirArray *` from `public\QirTypes.hpp`. -**intrinsics.cpp** Defines `quantum__qis__*()` gate set implementation. +**intrinsics.cpp** Defines `__quantum__qis__*()` gate set implementation. Each API depends on `GlobalContext()`, `IQuantumGateSet`. - -## Level 2 - -**qsharp-core-qis.ll** Defines `@__quantum__qis__*()` quantum gate set entry points (to be called by the `.ll` files generated from users' `.qs` files). - The C++ Standard reserves the identifiers starting with double underscores `__`, that is why the definitions of `@__quantum__qis__*` - have been put to `.ll` file rather than `.cpp` file. - Depends on `quantum__qis__*` implementations (in **intrinsics.cpp**). diff --git a/src/Qir/Runtime/lib/QSharpCore/intrinsics.cpp b/src/Qir/Runtime/lib/QSharpCore/intrinsics.cpp index 6b2a072ee48..97d14148521 100644 --- a/src/Qir/Runtime/lib/QSharpCore/intrinsics.cpp +++ b/src/Qir/Runtime/lib/QSharpCore/intrinsics.cpp @@ -37,46 +37,50 @@ static Microsoft::Quantum::IQuantumGateSet* GateSet() extern "C" { - void quantum__qis__exp__body(QirArray* paulis, double angle, QirArray* qubits) + void __quantum__qis__exp__body(QirArray* paulis, double angle, QirArray* qubits) { assert(paulis->count == qubits->count); std::vector pauliIds = ExtractPauliIds(paulis); - return GateSet()->Exp((long)(paulis->count), reinterpret_cast(pauliIds.data()), - reinterpret_cast(qubits->buffer), angle); + GateSet()->Exp((long)(paulis->count), reinterpret_cast(pauliIds.data()), + reinterpret_cast(qubits->buffer), angle); } - void quantum__qis__exp__adj(QirArray* paulis, double angle, QirArray* qubits) + void __quantum__qis__exp__adj(QirArray* paulis, double angle, QirArray* qubits) { - quantum__qis__exp__body(paulis, -angle, qubits); + __quantum__qis__exp__body(paulis, -angle, qubits); } - void quantum__qis__exp__ctl(QirArray* ctls, QirArray* paulis, double angle, QirArray* qubits) + void __quantum__qis__exp__ctl(QirArray* ctls, QirExpTuple* args) { - assert(paulis->count == qubits->count); + assert(args->paulis->count == args->targets->count); - std::vector pauliIds = ExtractPauliIds(paulis); - return GateSet()->ControlledExp((long)(ctls->count), reinterpret_cast(ctls->buffer), - (long)(paulis->count), reinterpret_cast(pauliIds.data()), - reinterpret_cast(qubits->buffer), angle); + std::vector pauliIds = ExtractPauliIds(args->paulis); + GateSet()->ControlledExp((long)(ctls->count), reinterpret_cast(ctls->buffer), + (long)(args->paulis->count), reinterpret_cast(pauliIds.data()), + reinterpret_cast(args->targets->buffer), args->angle); } - void quantum__qis__exp__ctladj(QirArray* ctls, QirArray* paulis, double angle, QirArray* qubits) + void __quantum__qis__exp__ctladj(QirArray* ctls, QirExpTuple* args) { - quantum__qis__exp__ctl(ctls, paulis, -angle, qubits); + assert(args->paulis->count == args->targets->count); + + QirExpTuple updatedArgs = {args->paulis, -(args->angle), args->targets}; + + __quantum__qis__exp__ctl(ctls, &updatedArgs); } - void quantum__qis__h__body(Qubit qubit) + void __quantum__qis__h__body(Qubit qubit) { GateSet()->H(qubit); } - void quantum__qis__h__ctl(QirArray* ctls, Qubit qubit) + void __quantum__qis__h__ctl(QirArray* ctls, Qubit qubit) { GateSet()->ControlledH((long)(ctls->count), reinterpret_cast(ctls->buffer), qubit); } - Result quantum__qis__measure__body(QirArray* paulis, QirArray* qubits) + Result __quantum__qis__measure__body(QirArray* paulis, QirArray* qubits) { const QirArray::TItemCount count = qubits->count; assert(count == paulis->count); @@ -86,92 +90,94 @@ extern "C" reinterpret_cast(qubits->buffer)); } - void quantum__qis__r__body(PauliId axis, double angle, QUBIT* qubit) + void __quantum__qis__r__body(PauliId axis, double angle, QUBIT* qubit) { - return GateSet()->R(axis, qubit, angle); + GateSet()->R(axis, qubit, angle); } - void quantum__qis__r__adj(PauliId axis, double angle, QUBIT* qubit) + void __quantum__qis__r__adj(PauliId axis, double angle, QUBIT* qubit) { - quantum__qis__r__body(axis, -angle, qubit); + __quantum__qis__r__body(axis, -angle, qubit); } - void quantum__qis__r__ctl(QirArray* ctls, PauliId axis, double angle, QUBIT* qubit) + void __quantum__qis__r__ctl(QirArray* ctls, QirRTuple* args) { - return GateSet()->ControlledR((long)(ctls->count), reinterpret_cast(ctls->buffer), axis, qubit, angle); + GateSet()->ControlledR((long)(ctls->count), reinterpret_cast(ctls->buffer), args->pauli, args->target, + args->angle); } - void quantum__qis__r__ctladj(QirArray* ctls, PauliId axis, double angle, QUBIT* qubit) + void __quantum__qis__r__ctladj(QirArray* ctls, QirRTuple* args) { - quantum__qis__r__ctl(ctls, axis, -angle, qubit); + GateSet()->ControlledR((long)(ctls->count), reinterpret_cast(ctls->buffer), args->pauli, args->target, + -(args->angle)); } - void quantum__qis__s__body(Qubit qubit) + void __quantum__qis__s__body(Qubit qubit) { GateSet()->S(qubit); } - void quantum__qis__s__adj(Qubit qubit) + void __quantum__qis__s__adj(Qubit qubit) { GateSet()->AdjointS(qubit); } - void quantum__qis__s__ctl(QirArray* ctls, Qubit qubit) + void __quantum__qis__s__ctl(QirArray* ctls, Qubit qubit) { GateSet()->ControlledS((long)(ctls->count), reinterpret_cast(ctls->buffer), qubit); } - void quantum__qis__s__ctladj(QirArray* ctls, Qubit qubit) + void __quantum__qis__s__ctladj(QirArray* ctls, Qubit qubit) { GateSet()->ControlledAdjointS((long)(ctls->count), reinterpret_cast(ctls->buffer), qubit); } - void quantum__qis__t__body(Qubit qubit) + void __quantum__qis__t__body(Qubit qubit) { GateSet()->T(qubit); } - void quantum__qis__t__adj(Qubit qubit) + void __quantum__qis__t__adj(Qubit qubit) { GateSet()->AdjointT(qubit); } - void quantum__qis__t__ctl(QirArray* ctls, Qubit qubit) + void __quantum__qis__t__ctl(QirArray* ctls, Qubit qubit) { GateSet()->ControlledT((long)(ctls->count), reinterpret_cast(ctls->buffer), qubit); } - void quantum__qis__t__ctladj(QirArray* ctls, Qubit qubit) + void __quantum__qis__t__ctladj(QirArray* ctls, Qubit qubit) { GateSet()->ControlledAdjointT((long)(ctls->count), reinterpret_cast(ctls->buffer), qubit); } - void quantum__qis__x__body(Qubit qubit) + void __quantum__qis__x__body(Qubit qubit) { GateSet()->X(qubit); } - void quantum__qis__x__ctl(QirArray* ctls, Qubit qubit) + void __quantum__qis__x__ctl(QirArray* ctls, Qubit qubit) { GateSet()->ControlledX((long)(ctls->count), reinterpret_cast(ctls->buffer), qubit); } - void quantum__qis__y__body(Qubit qubit) + void __quantum__qis__y__body(Qubit qubit) { GateSet()->Y(qubit); } - void quantum__qis__y__ctl(QirArray* ctls, Qubit qubit) + void __quantum__qis__y__ctl(QirArray* ctls, Qubit qubit) { GateSet()->ControlledY((long)(ctls->count), reinterpret_cast(ctls->buffer), qubit); } - void quantum__qis__z__body(Qubit qubit) + void __quantum__qis__z__body(Qubit qubit) { GateSet()->Z(qubit); } - void quantum__qis__z__ctl(QirArray* ctls, Qubit qubit) + void __quantum__qis__z__ctl(QirArray* ctls, Qubit qubit) { GateSet()->ControlledZ((long)(ctls->count), reinterpret_cast(ctls->buffer), qubit); } diff --git a/src/Qir/Runtime/lib/QSharpCore/intrinsicsDump.cpp b/src/Qir/Runtime/lib/QSharpCore/intrinsicsDump.cpp index 714235714f4..4d6dd714c5e 100644 --- a/src/Qir/Runtime/lib/QSharpCore/intrinsicsDump.cpp +++ b/src/Qir/Runtime/lib/QSharpCore/intrinsicsDump.cpp @@ -11,12 +11,12 @@ static Microsoft::Quantum::IDiagnostics* GetDiagnostics() // Implementation: extern "C" { - void quantum__qis__dumpmachine__body(uint8_t* location) + void __quantum__qis__dumpmachine__body(uint8_t* location) { GetDiagnostics()->DumpMachine(location); } - void quantum__qis__dumpregister__body(uint8_t* location, const QirArray* qubits) + void __quantum__qis__dumpregister__body(uint8_t* location, const QirArray* qubits) { GetDiagnostics()->DumpRegister(location, qubits); } diff --git a/src/Qir/Runtime/lib/QSharpCore/qsharp-core-qis.ll b/src/Qir/Runtime/lib/QSharpCore/qsharp-core-qis.ll deleted file mode 100644 index 66f2a1752bf..00000000000 --- a/src/Qir/Runtime/lib/QSharpCore/qsharp-core-qis.ll +++ /dev/null @@ -1,302 +0,0 @@ -; Copyright (c) Microsoft Corporation. -; Licensed under the MIT License. - -;======================================================================================================================= -; QIR types -; -%Array = type opaque -%Callable = type opaque -%Qubit = type opaque -%Range = type { i64, i64, i64 } -%Result = type opaque -%String = type opaque -%Pauli = type i2 - -;======================================================================================================================= -; Native types -; NB: there is no overloading at IR level, so a call/invoke will be made even -; if the definition of the function mismatches the declaration of the arguments. -; It means we could declare here the bridge's C-functions using QIR types -; and avoid bitcasts. However, it seems prudent to be more explicit about -; what's going on and declare the true signatures, as generated by Clang. -; -%class.QUBIT = type opaque -%class.RESULT = type opaque -%struct.QirArray = type opaque -%struct.QirCallable = type opaque -%struct.QirRange = type { i64, i64, i64 } -%struct.QirString = type opaque -%PauliId = type i32 - -; The __quantum__qis__* definitions should be automatically generated by QIR, depending on the specific target. -; However, for simulator targets we provide an optional simple bridge that covers commonly used intrinsics. - -;=============================================================================== -; declarations of the native methods this bridge delegates to -; -declare void @quantum__qis__exp__body(%struct.QirArray*, double, %struct.QirArray*) -declare void @quantum__qis__exp__adj(%struct.QirArray*, double, %struct.QirArray*) -declare void @quantum__qis__exp__ctl(%struct.QirArray*, %struct.QirArray*, double, %struct.QirArray*) -declare void @quantum__qis__exp__ctladj(%struct.QirArray*, %struct.QirArray*, double, %struct.QirArray*) -declare void @quantum__qis__h__body(%class.QUBIT*) -declare void @quantum__qis__h__ctl(%struct.QirArray*, %class.QUBIT*) -declare %class.RESULT* @quantum__qis__measure__body(%struct.QirArray*, %struct.QirArray*) -declare void @quantum__qis__r__body(i32, double, %class.QUBIT*) -declare void @quantum__qis__r__adj(i32, double, %class.QUBIT*) -declare void @quantum__qis__r__ctl(%struct.QirArray*, i32, double, %class.QUBIT*) -declare void @quantum__qis__r__ctladj(%struct.QirArray*, i32, double, %class.QUBIT*) -declare void @quantum__qis__s__body(%class.QUBIT*) -declare void @quantum__qis__s__adj(%class.QUBIT*) -declare void @quantum__qis__s__ctl(%struct.QirArray*, %class.QUBIT*) -declare void @quantum__qis__s__ctladj(%struct.QirArray*, %class.QUBIT*) -declare void @quantum__qis__t__body(%class.QUBIT*) -declare void @quantum__qis__t__adj(%class.QUBIT*) -declare void @quantum__qis__t__ctl(%struct.QirArray*, %class.QUBIT*) -declare void @quantum__qis__t__ctladj(%struct.QirArray*, %class.QUBIT*) -declare void @quantum__qis__x__body(%class.QUBIT*) -declare void @quantum__qis__x__ctl(%struct.QirArray*, %class.QUBIT*) -declare void @quantum__qis__y__body(%class.QUBIT*) -declare void @quantum__qis__y__ctl(%struct.QirArray*, %class.QUBIT*) -declare void @quantum__qis__z__body(%class.QUBIT*) -declare void @quantum__qis__z__ctl(%struct.QirArray*, %class.QUBIT*) - -;=============================================================================== -; quantum.qis dump functions declarations -; -; Must be `const void* %location`, but `void *` is invalid (LLVM), and `const` is not supported. -declare void @quantum__qis__dumpmachine__body(i8* %location) -declare void @quantum__qis__dumpregister__body(i8* %location, %struct.QirArray* %qubits) - - -;=============================================================================== -; quantum.qis namespace implementations -; - -define dllexport void @__quantum__qis__exp__body(%Array* %.paulis, double %angle, %Array* %.qubits) { - %paulis = bitcast %Array* %.paulis to %struct.QirArray* - %qubits = bitcast %Array* %.qubits to %struct.QirArray* - call void @quantum__qis__exp__body(%struct.QirArray* %paulis, double %angle, %struct.QirArray* %qubits) - ret void -} - -define dllexport void @__quantum__qis__exp__adj(%Array* %.paulis, double %angle, %Array* %.qubits) { - %paulis = bitcast %Array* %.paulis to %struct.QirArray* - %qubits = bitcast %Array* %.qubits to %struct.QirArray* - call void @quantum__qis__exp__adj(%struct.QirArray* %paulis, double %angle, %struct.QirArray* %qubits) - ret void -} - -define dllexport void @__quantum__qis__exp__ctl(%Array* %.ctls, {%Array*, double, %Array*}* %.args) { - %ctls = bitcast %Array* %.ctls to %struct.QirArray* - - %.ppaulis = getelementptr inbounds {%Array*, double, %Array*}, {%Array*, double, %Array*}* %.args, i32 0, i32 0 - %.paulis = load %Array*, %Array** %.ppaulis - %paulis = bitcast %Array* %.paulis to %struct.QirArray* - - %.pangle = getelementptr inbounds {%Array*, double, %Array*}, {%Array*, double, %Array*}* %.args, i32 0, i32 1 - %angle = load double, double* %.pangle - - %.pqubits = getelementptr inbounds {%Array*, double, %Array*}, {%Array*, double, %Array*}* %.args, i32 0, i32 2 - %.qubits = load %Array*, %Array** %.pqubits - %qubits = bitcast %Array* %.qubits to %struct.QirArray* - - call void @quantum__qis__exp__ctl( - %struct.QirArray* %ctls, %struct.QirArray* %paulis, double %angle, %struct.QirArray* %qubits) - ret void -} - -define dllexport void @__quantum__qis__exp__ctladj(%Array* %.ctls, { %Array*, double, %Array* }* %.args) { - %ctls = bitcast %Array* %.ctls to %struct.QirArray* - - %.ppaulis = getelementptr inbounds {%Array*, double, %Array*}, {%Array*, double, %Array*}* %.args, i32 0, i32 0 - %.paulis = load %Array*, %Array** %.ppaulis - %paulis = bitcast %Array* %.paulis to %struct.QirArray* - - %.pangle = getelementptr inbounds {%Array*, double, %Array*}, {%Array*, double, %Array*}* %.args, i32 0, i32 1 - %angle = load double, double* %.pangle - - %.pqubits = getelementptr inbounds {%Array*, double, %Array*}, {%Array*, double, %Array*}* %.args, i32 0, i32 2 - %.qubits = load %Array*, %Array** %.pqubits - %qubits = bitcast %Array* %.qubits to %struct.QirArray* - - call void @quantum__qis__exp__ctladj( - %struct.QirArray* %ctls, %struct.QirArray* %paulis, double %angle, %struct.QirArray* %qubits) - ret void -} - -define dllexport void @__quantum__qis__h__body(%Qubit* %.q) { - %q = bitcast %Qubit* %.q to %class.QUBIT* - call void @quantum__qis__h__body(%class.QUBIT* %q) - ret void -} - -define dllexport void @__quantum__qis__h__ctl(%Array* %.ctls, %Qubit* %.q) { - %q = bitcast %Qubit* %.q to %class.QUBIT* - %ctls = bitcast %Array* %.ctls to %struct.QirArray* - call void @quantum__qis__h__ctl(%struct.QirArray* %ctls, %class.QUBIT* %q) - ret void -} - -define dllexport %Result* @__quantum__qis__measure__body(%Array* %.paulis, %Array* %.qubits) { - %paulis = bitcast %Array* %.paulis to %struct.QirArray* - %qubits = bitcast %Array* %.qubits to %struct.QirArray* - %r = call %class.RESULT* @quantum__qis__measure__body(%struct.QirArray* %paulis, %struct.QirArray* %qubits) - %.r = bitcast %class.RESULT* %r to %Result* - ret %Result* %.r -} - -define dllexport void @__quantum__qis__r__body(%Pauli %.pauli, double %theta, %Qubit* %.q) { - %q = bitcast %Qubit* %.q to %class.QUBIT* - %pauli = zext %Pauli %.pauli to %PauliId - call void @quantum__qis__r__body(%PauliId %pauli, double %theta, %class.QUBIT* %q) - ret void -} - -define dllexport void @__quantum__qis__r__adj(%Pauli %.pauli, double %theta, %Qubit* %.q) { - %q = bitcast %Qubit* %.q to %class.QUBIT* - %pauli = zext %Pauli %.pauli to %PauliId - call void @quantum__qis__r__adj(%PauliId %pauli, double %theta, %class.QUBIT* %q) - ret void -} - -define dllexport void @__quantum__qis__r__ctl(%Array* %.ctls, {%Pauli, double, %Qubit*}* %.args) { - %ctls = bitcast %Array* %.ctls to %struct.QirArray* - - %.ppauli = getelementptr inbounds {%Pauli, double, %Qubit*}, {%Pauli, double, %Qubit*}* %.args, i32 0, i32 0 - %.pauli = load %Pauli, %Pauli* %.ppauli - %pauli = zext %Pauli %.pauli to %PauliId - - %.ptheta = getelementptr inbounds {%Pauli, double, %Qubit*}, {%Pauli, double, %Qubit*}* %.args, i32 0, i32 1 - %theta = load double, double* %.ptheta - - %.pq = getelementptr inbounds {%Pauli, double, %Qubit*}, {%Pauli, double, %Qubit*}* %.args, i32 0, i32 2 - %.q = load %Qubit*, %Qubit** %.pq - %q = bitcast %Qubit* %.q to %class.QUBIT* - - call void @quantum__qis__r__ctl(%struct.QirArray* %ctls, %PauliId %pauli, double %theta, %class.QUBIT* %q) - ret void -} - -define dllexport void @__quantum__qis__r__ctladj(%Array* %.ctls, {%Pauli, double, %Qubit*}* %.args) { - %ctls = bitcast %Array* %.ctls to %struct.QirArray* - - %.ppauli = getelementptr inbounds {%Pauli, double, %Qubit*}, {%Pauli, double, %Qubit*}* %.args, i32 0, i32 0 - %.pauli = load %Pauli, %Pauli* %.ppauli - %pauli = zext %Pauli %.pauli to %PauliId - - %.ptheta = getelementptr inbounds {%Pauli, double, %Qubit*}, {%Pauli, double, %Qubit*}* %.args, i32 0, i32 1 - %theta = load double, double* %.ptheta - - %.pq = getelementptr inbounds {%Pauli, double, %Qubit*}, {%Pauli, double, %Qubit*}* %.args, i32 0, i32 2 - %.q = load %Qubit*, %Qubit** %.pq - %q = bitcast %Qubit* %.q to %class.QUBIT* - - call void @quantum__qis__r__ctladj(%struct.QirArray* %ctls, %PauliId %pauli, double %theta, %class.QUBIT* %q) - ret void -} - -define dllexport void @__quantum__qis__s__body(%Qubit* %.q) { - %q = bitcast %Qubit* %.q to %class.QUBIT* - call void @quantum__qis__s__body(%class.QUBIT* %q) - ret void -} - -define dllexport void @__quantum__qis__s__adj(%Qubit* %.q) { - %q = bitcast %Qubit* %.q to %class.QUBIT* - call void @quantum__qis__s__adj(%class.QUBIT* %q) - ret void -} - -define dllexport void @__quantum__qis__s__ctl(%Array* %.ctls, %Qubit* %.q) { - %q = bitcast %Qubit* %.q to %class.QUBIT* - %ctls = bitcast %Array* %.ctls to %struct.QirArray* - call void @quantum__qis__s__ctl(%struct.QirArray* %ctls, %class.QUBIT* %q) - ret void -} - -define dllexport void @__quantum__qis__s__ctladj(%Array* %.ctls, %Qubit* %.q) { - %q = bitcast %Qubit* %.q to %class.QUBIT* - %ctls = bitcast %Array* %.ctls to %struct.QirArray* - call void @quantum__qis__s__ctladj(%struct.QirArray* %ctls, %class.QUBIT* %q) - ret void -} - -define dllexport void @__quantum__qis__t__body(%Qubit* %.q) { - %q = bitcast %Qubit* %.q to %class.QUBIT* - call void @quantum__qis__t__body(%class.QUBIT* %q) - ret void -} - -define dllexport void @__quantum__qis__t__adj(%Qubit* %.q) { - %q = bitcast %Qubit* %.q to %class.QUBIT* - call void @quantum__qis__t__adj(%class.QUBIT* %q) - ret void -} - -define dllexport void @__quantum__qis__t__ctl(%Array* %.ctls, %Qubit* %.q) { - %q = bitcast %Qubit* %.q to %class.QUBIT* - %ctls = bitcast %Array* %.ctls to %struct.QirArray* - call void @quantum__qis__t__ctl(%struct.QirArray* %ctls, %class.QUBIT* %q) - ret void -} - -define dllexport void @__quantum__qis__t__ctladj(%Array* %.ctls, %Qubit* %.q) { - %q = bitcast %Qubit* %.q to %class.QUBIT* - %ctls = bitcast %Array* %.ctls to %struct.QirArray* - call void @quantum__qis__t__ctladj(%struct.QirArray* %ctls, %class.QUBIT* %q) - ret void -} - -define dllexport void @__quantum__qis__x__body(%Qubit* %.q) { - %q = bitcast %Qubit* %.q to %class.QUBIT* - call void @quantum__qis__x__body(%class.QUBIT* %q) - ret void -} - -define dllexport void @__quantum__qis__x__ctl(%Array* %.ctls, %Qubit* %.q) { - %q = bitcast %Qubit* %.q to %class.QUBIT* - %ctls = bitcast %Array* %.ctls to %struct.QirArray* - call void @quantum__qis__x__ctl(%struct.QirArray* %ctls, %class.QUBIT* %q) - ret void -} - -define dllexport void @__quantum__qis__y__body(%Qubit* %.q) { - %q = bitcast %Qubit* %.q to %class.QUBIT* - call void @quantum__qis__y__body(%class.QUBIT* %q) - ret void -} - -define dllexport void @__quantum__qis__y__ctl(%Array* %.ctls, %Qubit* %.q) { - %q = bitcast %Qubit* %.q to %class.QUBIT* - %ctls = bitcast %Array* %.ctls to %struct.QirArray* - call void @quantum__qis__y__ctl(%struct.QirArray* %ctls, %class.QUBIT* %q) - ret void -} - -define dllexport void @__quantum__qis__z__body(%Qubit* %.q) { - %q = bitcast %Qubit* %.q to %class.QUBIT* - call void @quantum__qis__z__body(%class.QUBIT* %q) - ret void -} - -define dllexport void @__quantum__qis__z__ctl(%Array* %.ctls, %Qubit* %.q) { - %q = bitcast %Qubit* %.q to %class.QUBIT* - %ctls = bitcast %Array* %.ctls to %struct.QirArray* - call void @quantum__qis__z__ctl(%struct.QirArray* %ctls, %class.QUBIT* %q) - ret void -} - - -;=============================================================================== -; quantum.qis dump functions implementation -; -define dllexport void @__quantum__qis__dumpmachine__body(i8* %location) { - call void @quantum__qis__dumpmachine__body(i8* %location) - ret void -} - -define dllexport void @__quantum__qis__dumpregister__body(i8* %location, %Array* %.qubits) { - %qubits = bitcast %Array* %.qubits to %struct.QirArray* - call void @quantum__qis__dumpregister__body(i8* %location, %struct.QirArray* %qubits) - ret void -} diff --git a/src/Qir/Runtime/lib/QSharpCore/qsharp__core__qis.hpp b/src/Qir/Runtime/lib/QSharpCore/qsharp__core__qis.hpp index 908a8ed5085..ebbd1a5987c 100644 --- a/src/Qir/Runtime/lib/QSharpCore/qsharp__core__qis.hpp +++ b/src/Qir/Runtime/lib/QSharpCore/qsharp__core__qis.hpp @@ -7,6 +7,20 @@ struct QirArray; +struct QirRTuple +{ + PauliId pauli; + double angle; + QUBIT* target; +}; + +struct QirExpTuple +{ + QirArray* paulis; + double angle; + QirArray* targets; +}; + /* Methods from __quantum__qis namespace are specific to the target. When QIR is generated it might limit or extend the set of intrinsics, supported by the target (known to QIR generator at compile time). This provides the @@ -15,35 +29,35 @@ struct QirArray; extern "C" { // Q# Gate Set - QIR_SHARED_API void quantum__qis__exp__body(QirArray*, double, QirArray*); // NOLINT - QIR_SHARED_API void quantum__qis__exp__adj(QirArray*, double, QirArray*); // NOLINT - QIR_SHARED_API void quantum__qis__exp__ctl(QirArray*, QirArray*, double, QirArray*); // NOLINT - QIR_SHARED_API void quantum__qis__exp__ctladj(QirArray*, QirArray*, double, QirArray*); // NOLINT - QIR_SHARED_API void quantum__qis__h__body(QUBIT*); // NOLINT - QIR_SHARED_API void quantum__qis__h__ctl(QirArray*, QUBIT*); // NOLINT - QIR_SHARED_API RESULT* quantum__qis__measure__body(QirArray*, QirArray*); // NOLINT - QIR_SHARED_API void quantum__qis__r__body(PauliId, double, QUBIT*); // NOLINT - QIR_SHARED_API void quantum__qis__r__adj(PauliId, double, QUBIT*); // NOLINT - QIR_SHARED_API void quantum__qis__r__ctl(QirArray*, PauliId, double, QUBIT*); // NOLINT - QIR_SHARED_API void quantum__qis__r__ctladj(QirArray*, PauliId, double, QUBIT*); // NOLINT - QIR_SHARED_API void quantum__qis__s__body(QUBIT*); // NOLINT - QIR_SHARED_API void quantum__qis__s__adj(QUBIT*); // NOLINT - QIR_SHARED_API void quantum__qis__s__ctl(QirArray*, QUBIT*); // NOLINT - QIR_SHARED_API void quantum__qis__s__ctladj(QirArray*, QUBIT*); // NOLINT - QIR_SHARED_API void quantum__qis__t__body(QUBIT*); // NOLINT - QIR_SHARED_API void quantum__qis__t__adj(QUBIT*); // NOLINT - QIR_SHARED_API void quantum__qis__t__ctl(QirArray*, QUBIT*); // NOLINT - QIR_SHARED_API void quantum__qis__t__ctladj(QirArray*, QUBIT*); // NOLINT - QIR_SHARED_API void quantum__qis__x__body(QUBIT*); // NOLINT - QIR_SHARED_API void quantum__qis__x__ctl(QirArray*, QUBIT*); // NOLINT - QIR_SHARED_API void quantum__qis__y__body(QUBIT*); // NOLINT - QIR_SHARED_API void quantum__qis__y__ctl(QirArray*, QUBIT*); // NOLINT - QIR_SHARED_API void quantum__qis__z__body(QUBIT*); // NOLINT - QIR_SHARED_API void quantum__qis__z__ctl(QirArray*, QUBIT*); // NOLINT + QIR_SHARED_API void __quantum__qis__exp__body(QirArray*, double, QirArray*); // NOLINT + QIR_SHARED_API void __quantum__qis__exp__adj(QirArray*, double, QirArray*); // NOLINT + QIR_SHARED_API void __quantum__qis__exp__ctl(QirArray*, QirExpTuple*); // NOLINT + QIR_SHARED_API void __quantum__qis__exp__ctladj(QirArray*, QirExpTuple*); // NOLINT + QIR_SHARED_API void __quantum__qis__h__body(QUBIT*); // NOLINT + QIR_SHARED_API void __quantum__qis__h__ctl(QirArray*, QUBIT*); // NOLINT + QIR_SHARED_API RESULT* __quantum__qis__measure__body(QirArray*, QirArray*); // NOLINT + QIR_SHARED_API void __quantum__qis__r__body(PauliId, double, QUBIT*); // NOLINT + QIR_SHARED_API void __quantum__qis__r__adj(PauliId, double, QUBIT*); // NOLINT + QIR_SHARED_API void __quantum__qis__r__ctl(QirArray*, QirRTuple*); // NOLINT + QIR_SHARED_API void __quantum__qis__r__ctladj(QirArray*, QirRTuple*); // NOLINT + QIR_SHARED_API void __quantum__qis__s__body(QUBIT*); // NOLINT + QIR_SHARED_API void __quantum__qis__s__adj(QUBIT*); // NOLINT + QIR_SHARED_API void __quantum__qis__s__ctl(QirArray*, QUBIT*); // NOLINT + QIR_SHARED_API void __quantum__qis__s__ctladj(QirArray*, QUBIT*); // NOLINT + QIR_SHARED_API void __quantum__qis__t__body(QUBIT*); // NOLINT + QIR_SHARED_API void __quantum__qis__t__adj(QUBIT*); // NOLINT + QIR_SHARED_API void __quantum__qis__t__ctl(QirArray*, QUBIT*); // NOLINT + QIR_SHARED_API void __quantum__qis__t__ctladj(QirArray*, QUBIT*); // NOLINT + QIR_SHARED_API void __quantum__qis__x__body(QUBIT*); // NOLINT + QIR_SHARED_API void __quantum__qis__x__ctl(QirArray*, QUBIT*); // NOLINT + QIR_SHARED_API void __quantum__qis__y__body(QUBIT*); // NOLINT + QIR_SHARED_API void __quantum__qis__y__ctl(QirArray*, QUBIT*); // NOLINT + QIR_SHARED_API void __quantum__qis__z__body(QUBIT*); // NOLINT + QIR_SHARED_API void __quantum__qis__z__ctl(QirArray*, QUBIT*); // NOLINT // Q# Dump: // Note: The param `location` must be `const void*`, // but it is called from .ll, where `const void*` is not supported. - QIR_SHARED_API void quantum__qis__dumpmachine__body(uint8_t* location); // NOLINT - QIR_SHARED_API void quantum__qis__dumpregister__body(uint8_t* location, const QirArray* qubits); // NOLINT + QIR_SHARED_API void __quantum__qis__dumpmachine__body(uint8_t* location); // NOLINT + QIR_SHARED_API void __quantum__qis__dumpregister__body(uint8_t* location, const QirArray* qubits); // NOLINT } diff --git a/src/Qir/Runtime/lib/QSharpFoundation/AssertMeasurement.cpp b/src/Qir/Runtime/lib/QSharpFoundation/AssertMeasurement.cpp index 583779fd868..1315a465211 100644 --- a/src/Qir/Runtime/lib/QSharpFoundation/AssertMeasurement.cpp +++ b/src/Qir/Runtime/lib/QSharpFoundation/AssertMeasurement.cpp @@ -18,13 +18,13 @@ static IDiagnostics* GetDiagnostics() // Implementation: extern "C" { - void quantum__qis__assertmeasurementprobability__body(QirArray* bases, QirArray* qubits, RESULT* result, - double prob, QirString* msg, double tol) + void __quantum__qis__assertmeasurementprobability__body(QirArray* bases, QirArray* qubits, RESULT* result, + double prob, QirString* msg, double tol) { if (bases->count != qubits->count) { - quantum__rt__fail_cstr("Both input arrays - bases, qubits - for AssertMeasurementProbability(), " - "must be of same size."); + __quantum__rt__fail_cstr("Both input arrays - bases, qubits - for AssertMeasurementProbability(), " + "must be of same size."); } IRuntimeDriver* driver = GlobalContext()->GetDriver(); @@ -44,8 +44,17 @@ extern "C" reinterpret_cast(qubits->GetItemPointer(0)), prob, tol, nullptr)) { - quantum__rt__fail(msg); + __quantum__rt__fail(msg); } } + void __quantum__qis__assertmeasurementprobability__ctl(QirArray* /* ctls */, + QirAssertMeasurementProbabilityTuple* args) + { + // Controlled AssertMeasurementProbability ignores control bits. See the discussion on + // https://github.com/microsoft/qsharp-runtime/pull/450 for more details. + __quantum__qis__assertmeasurementprobability__body(args->bases, args->qubits, args->result, args->prob, + args->msg, args->tol); + } + } // extern "C" diff --git a/src/Qir/Runtime/lib/QSharpFoundation/CMakeLists.txt b/src/Qir/Runtime/lib/QSharpFoundation/CMakeLists.txt index 4a2f9e76573..744d94c86a1 100644 --- a/src/Qir/Runtime/lib/QSharpFoundation/CMakeLists.txt +++ b/src/Qir/Runtime/lib/QSharpFoundation/CMakeLists.txt @@ -13,7 +13,6 @@ set(qsharp_foundation_sup_source_files # 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(qsharp-foundation-qis-support-obj qsharp-foundation-qis.ll) target_include_directories(qsharp-foundation-qis-support-obj PUBLIC ${public_includes} ${common_includes} diff --git a/src/Qir/Runtime/lib/QSharpFoundation/README.md b/src/Qir/Runtime/lib/QSharpFoundation/README.md index f7b22c204f9..bf373827db2 100644 --- a/src/Qir/Runtime/lib/QSharpFoundation/README.md +++ b/src/Qir/Runtime/lib/QSharpFoundation/README.md @@ -17,15 +17,15 @@ Same-level entities are independent of each other (unless specified otherwise). **public\QirTypes.hpp** Defines `QirArray`, `QirString`, `PTuple`, `QirTupleHeader`, `TupleWithControls`, `QirCallable`, `QirRange`. Depends on the listed earlier ones. -**public\QirRuntime.hpp** Declares `quantum__rt__*()`. Depends on the listed earlier ones. +**public\QirRuntime.hpp** Declares `__quantum__rt__*()`. Depends on the listed earlier ones. ## Level 1 -**conditionals.cpp** Defines `quantum__qis__apply*__body()`. +**conditionals.cpp** Defines `__quantum__qis__apply*__body()`. Depends on QIR's `quantum__rt__result_{equal,get_zero}()`, declared in **public\QirRuntime.hpp**. -**intrinsicsMath.cpp** Defines `quantum__qis__*` math funcs implementations, +**intrinsicsMath.cpp** Defines `__quantum__qis__*` math funcs implementations, `Quantum::Qis::Internal::{excStrDrawRandomVal,RandomizeSeed,GetLastGeneratedRandomI64,GetLastGeneratedRandomDouble}`. Depends on `quantum__rt__fail()`, `quantum__rt__string_create()`, declared in **public\QirRuntime.hpp**. @@ -33,9 +33,5 @@ Same-level entities are independent of each other (unless specified otherwise). ## Level 2 **qsharp__foundation__qis.hpp** - Declares `quantum__qis__*()` math funcs and ApplyIf. + Declares `__quantum__qis__*()` math funcs and ApplyIf. Depends on **public\CoreTypes.hpp**, **public\QirTypes.hpp**. - -**qsharp-foundation-qis.ll** - Defines `@__quantum__qis__*()` math funcs and ApplyIf - entry points (to be called by the `.ll` files generated from users' `.qs` files). - Depends on `quantum__qis__*` implementations (in **intrinsicsMath.cpp**, **conditionals.cpp**, ). diff --git a/src/Qir/Runtime/lib/QSharpFoundation/conditionals.cpp b/src/Qir/Runtime/lib/QSharpFoundation/conditionals.cpp index 6123a4300a9..c7df89fbd6c 100644 --- a/src/Qir/Runtime/lib/QSharpFoundation/conditionals.cpp +++ b/src/Qir/Runtime/lib/QSharpFoundation/conditionals.cpp @@ -19,7 +19,7 @@ static bool ArraysContainEqualResults(QirArray* rs1, QirArray* rs2) RESULT** results2 = reinterpret_cast(rs2->buffer); for (QirArray::TItemCount i = 0; i < rs1->count; i++) { - if (!quantum__rt__result_equal(results1[i], results2[i])) + if (!__quantum__rt__result_equal(results1[i], results2[i])) { return false; } @@ -29,14 +29,14 @@ static bool ArraysContainEqualResults(QirArray* rs1, QirArray* rs2) extern "C" { - void quantum__qis__applyifelseintrinsic__body(RESULT* r, QirCallable* clbOnZero, QirCallable* clbOnOne) + void __quantum__qis__applyifelseintrinsic__body(RESULT* r, QirCallable* clbOnZero, QirCallable* clbOnOne) { - QirCallable* clb = quantum__rt__result_equal(r, quantum__rt__result_get_zero()) ? clbOnZero : clbOnOne; + QirCallable* clb = __quantum__rt__result_equal(r, __quantum__rt__result_get_zero()) ? clbOnZero : clbOnOne; clb->Invoke(); } - void quantum__qis__applyconditionallyintrinsic__body(QirArray* rs1, QirArray* rs2, QirCallable* clbOnAllEqual, - QirCallable* clbOnSomeDifferent) + void __quantum__qis__applyconditionallyintrinsic__body(QirArray* rs1, QirArray* rs2, QirCallable* clbOnAllEqual, + QirCallable* clbOnSomeDifferent) { QirCallable* clb = ArraysContainEqualResults(rs1, rs2) ? clbOnAllEqual : clbOnSomeDifferent; clb->Invoke(); diff --git a/src/Qir/Runtime/lib/QSharpFoundation/intrinsicsMath.cpp b/src/Qir/Runtime/lib/QSharpFoundation/intrinsicsMath.cpp index 594327fcc3e..3a748101f35 100644 --- a/src/Qir/Runtime/lib/QSharpFoundation/intrinsicsMath.cpp +++ b/src/Qir/Runtime/lib/QSharpFoundation/intrinsicsMath.cpp @@ -21,61 +21,101 @@ extern "C" { // Implementations: - bool quantum__qis__isnan__body(double d) + double __quantum__qis__nan__body() + { + return std::sqrt(-1.0); // sqrt() -> NaN + } + + bool __quantum__qis__isnan__body(double d) { return std::isnan(d); // https://en.cppreference.com/w/cpp/numeric/math/isnan } - double quantum__qis__infinity__body() + double __quantum__qis__infinity__body() { return (double)INFINITY; // https://en.cppreference.com/w/c/numeric/math/INFINITY } - bool quantum__qis__isinf__body(double d) + bool __quantum__qis__isinf__body(double d) + { + return std::isinf(d) && d > 0.0; // https://en.cppreference.com/w/cpp/numeric/math/isinf + } + + bool __quantum__qis__isnegativeinfinity__body(double d) + { + return std::isinf(d) && d < 0.0; // https://en.cppreference.com/w/cpp/numeric/math/isinf + } + + double __quantum__qis__sin__body(double d) + { + return std::sin(d); + } + + double __quantum__qis__cos__body(double d) { - return std::isinf(d); // https://en.cppreference.com/w/cpp/numeric/math/isinf + return std::cos(d); } - double quantum__qis__arctan2__body(double y, double x) + double __quantum__qis__tan__body(double d) + { + return std::tan(d); + } + + double __quantum__qis__arctan2__body(double y, double x) { return std::atan2(y, x); // https://en.cppreference.com/w/cpp/numeric/math/atan2 } - double quantum__qis__sinh__body(double theta) + double __quantum__qis__sinh__body(double theta) { return std::sinh(theta); } - double quantum__qis__cosh__body(double theta) + double __quantum__qis__cosh__body(double theta) { return std::cosh(theta); } - double quantum__qis__arcsin__body(double theta) + double __quantum__qis__tanh__body(double theta) + { + return std::tanh(theta); + } + + double __quantum__qis__arcsin__body(double theta) { return std::asin(theta); // https://en.cppreference.com/w/cpp/numeric/math/asin } - double quantum__qis__arccos__body(double theta) + double __quantum__qis__arccos__body(double theta) { return std::acos(theta); // https://en.cppreference.com/w/cpp/numeric/math/acos } - double quantum__qis__arctan__body(double theta) + double __quantum__qis__arctan__body(double theta) { return std::atan(theta); // https://en.cppreference.com/w/cpp/numeric/math/atan } - double quantum__qis__ieeeremainder__body(double x, double y) + double __quantum__qis__sqrt__body(double d) + { + return std::sqrt(d); + } + + double __quantum__qis__log__body(double d) + { + return std::log(d); + } + + double __quantum__qis__ieeeremainder__body(double x, double y) { return std::remainder(x, y); // https://en.cppreference.com/w/cpp/numeric/math/remainder } - int64_t quantum__qis__drawrandomint__body(int64_t minimum, int64_t maximum) + int64_t __quantum__qis__drawrandomint__body(int64_t minimum, int64_t maximum) { if (minimum > maximum) { - quantum__rt__fail_cstr(Quantum::Qis::Internal::excStrDrawRandomVal); + __quantum__rt__fail_cstr(Quantum::Qis::Internal::excStrDrawRandomVal); } // https://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution @@ -87,11 +127,11 @@ extern "C" return lastGeneratedRndI64; } - double quantum__qis__drawrandomdouble__body(double minimum, double maximum) + double __quantum__qis__drawrandomdouble__body(double minimum, double maximum) { if (minimum > maximum) { - quantum__rt__fail_cstr(Quantum::Qis::Internal::excStrDrawRandomVal); + __quantum__rt__fail_cstr(Quantum::Qis::Internal::excStrDrawRandomVal); } // For testing purposes we need separate generators for Int and Double: diff --git a/src/Qir/Runtime/lib/QSharpFoundation/qsharp-foundation-qis.ll b/src/Qir/Runtime/lib/QSharpFoundation/qsharp-foundation-qis.ll deleted file mode 100644 index 2b295a6c80d..00000000000 --- a/src/Qir/Runtime/lib/QSharpFoundation/qsharp-foundation-qis.ll +++ /dev/null @@ -1,272 +0,0 @@ -; Copyright (c) Microsoft Corporation. -; Licensed under the MIT License. - -; The __quantum__qis__* definitions should be automatically generated by QIR, depending on the specific target. -; However, for simulator targets we provide an optional simple bridge that covers commonly used intrinsics. - -;======================================================================================================================= -; QIR types -; -%Array = type opaque -%Callable = type opaque -%Qubit = type opaque -%Range = type { i64, i64, i64 } -%Result = type opaque -%String = type opaque -%Pauli = type i2 - -;======================================================================================================================= -; Native types -; NB: there is no overloading at IR level, so a call/invoke will be made even -; if the definition of the function mismatches the declaration of the arguments. -; It means we could declare here the bridge's C-functions using QIR types -; and avoid bitcasts. However, it seems prudent to be more explicit about -; what's going on and declare the true signatures, as generated by Clang. -; -%class.QUBIT = type opaque -%class.RESULT = type opaque -%struct.QirArray = type opaque -%struct.QirCallable = type opaque -%struct.QirRange = type { i64, i64, i64 } -%struct.QirString = type opaque -%PauliId = type i32 - -;=============================================================================== -; quantum.qis math functions declarations -; - -; LLVM intrinsics (https://llvm.org/docs/LangRef.html): -; TODO: consider calling these directly from the compiler-generated .ll code, rather than through the QIR. #632 -declare double @llvm.sqrt.f64(double %.val) -declare double @llvm.log.f64(double %Val) -declare double @llvm.sin.f64(double %Val) -declare double @llvm.cos.f64(double %Val) - -; Native implementations: -declare i1 @quantum__qis__isnan__body(double %d) -declare double @quantum__qis__infinity__body() -declare i1 @quantum__qis__isinf__body(double %d) -declare double @quantum__qis__arctan2__body(double %y, double %x) -declare double @quantum__qis__sinh__body(double %theta) -declare double @quantum__qis__cosh__body(double %theta) -declare double @quantum__qis__arcsin__body(double %theta) -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) - -;=============================================================================== -; quantum.qis conditional functions declarations -; -declare void @quantum__qis__applyifelseintrinsic__body(%class.RESULT*, %struct.QirCallable*, %struct.QirCallable*) -declare void @quantum__qis__applyconditionallyintrinsic__body( - %struct.QirArray*, %struct.QirArray*, %struct.QirCallable*, %struct.QirCallable*) - -;=============================================================================== -; quantum.qis Assert Measurement functions/operations declarations -; -declare void @quantum__qis__assertmeasurementprobability__body( - %struct.QirArray* %bases, %struct.QirArray* %qubits, %class.RESULT* %result, double %prob, %struct.QirString* %msg, double %tol) - -;=============================================================================== -; quantum.qis math functions implementation -; -; API for the user code: -define dllexport double @__quantum__qis__nan__body() { ; Q#: function NAN() : Double http://www.cplusplus.com/reference/cmath/nan-function/ - %result = call double @llvm.sqrt.f64(double -1.0) ; sqrt() -> NaN - ret double %result -} - -define dllexport i1 @__quantum__qis__isnan__body(double %d) { ; http://www.cplusplus.com/reference/cmath/isnan/ - %result = call i1 @quantum__qis__isnan__body(double %d) - ret i1 %result -} - -define dllexport double @__quantum__qis__infinity__body() { ; https://en.cppreference.com/w/c/numeric/math/INFINITY - %result = call double @quantum__qis__infinity__body() - ret double %result -} - -define dllexport i1 @__quantum__qis__isinf__body(double %d) { ; https://en.cppreference.com/w/cpp/numeric/math/isinf - %result = call i1 @quantum__qis__isinf__body(double %d) - ret i1 %result -} - -define dllexport double @__quantum__qis__sqrt__body(double %d) { ; https://en.cppreference.com/w/cpp/numeric/math/sqrt - %result = call double @llvm.sqrt.f64(double %d) - ret double %result -} - -define dllexport double @__quantum__qis__log__body(double %d) { ; https://en.cppreference.com/w/cpp/numeric/math/log - %result = call double @llvm.log.f64(double %d) - ret double %result -} - -define dllexport i1 @__quantum__qis__isnegativeinfinity__body(double %d) { ; Q#: function IsNegativeInfinity(d : Double) : Bool - ; https://en.cppreference.com/w/cpp/numeric/math/log https://llvm.org/docs/LangRef.html#llvm-log-intrinsic - %negInf = call double @llvm.log.f64(double 0.0) ; ln(0) -> (-infinity) - %result = fcmp oeq double %negInf, %d ; %result = (%negInf == %d) - ret i1 %result -} - -define dllexport double @__quantum__qis__arctan2__body(double %y, double %x) { ; Q#: function ArcTan2 (y : Double, x : Double) : Double - ; https://en.cppreference.com/w/cpp/numeric/math/atan2 - %result = call double @quantum__qis__arctan2__body(double %y, double %x) - ret double %result -} - -; function Sin (theta : Double) : Double -; https://docs.microsoft.com/qsharp/api/qsharp/microsoft.quantum.math.sin -define dllexport double @__quantum__qis__sin__body(double %theta) { ; https://en.cppreference.com/w/cpp/numeric/math/sin - %result = call double @llvm.sin.f64(double %theta) ; https://llvm.org/docs/LangRef.html#llvm-sin-intrinsic - ret double %result -} - -; function Cos (theta : Double) : Double -; https://docs.microsoft.com/qsharp/api/qsharp/microsoft.quantum.math.cos -define dllexport double @__quantum__qis__cos__body(double %theta) { ; https://en.cppreference.com/w/cpp/numeric/math/cos - %result = call double @llvm.cos.f64(double %theta) ; https://llvm.org/docs/LangRef.html#llvm-cos-intrinsic - ret double %result -} - -; function Tan (theta : Double) : Double -; https://docs.microsoft.com/qsharp/api/qsharp/microsoft.quantum.math.tan -define dllexport double @__quantum__qis__tan__body(double %theta) { ; https://en.cppreference.com/w/cpp/numeric/math/tan - %sin = call double @llvm.sin.f64(double %theta) - %cos = call double @llvm.cos.f64(double %theta) - %result = fdiv double %sin, %cos ; tg(x) = sin(x) / cos(x) - ret double %result -} - -; function Sinh (theta : Double) : Double -; https://docs.microsoft.com/qsharp/api/qsharp/microsoft.quantum.math.sinh -define dllexport double @__quantum__qis__sinh__body(double %theta) { ; https://en.cppreference.com/w/cpp/numeric/math/sinh - %result = call double @quantum__qis__sinh__body(double %theta) - ret double %result -} - -; function Cosh (theta : Double) : Double -; https://docs.microsoft.com/qsharp/api/qsharp/microsoft.quantum.math.cosh -define dllexport double @__quantum__qis__cosh__body(double %theta) { ; https://en.cppreference.com/w/cpp/numeric/math/cosh - %result = call double @quantum__qis__cosh__body(double %theta) - ret double %result -} - -; function Tanh (theta : Double) : Double -; https://docs.microsoft.com/qsharp/api/qsharp/microsoft.quantum.math.tanh -define dllexport double @__quantum__qis__tanh__body(double %theta) { ; https://en.cppreference.com/w/cpp/numeric/math/tanh - %sin = call double @__quantum__qis__sinh__body(double %theta) - %cos = call double @__quantum__qis__cosh__body(double %theta) - %result = fdiv double %sin, %cos ; tanh(x) = sinh(x) / cosh(x) - ret double %result -} - -; function ArcSin (theta : Double) : Double -; https://docs.microsoft.com/qsharp/api/qsharp/microsoft.quantum.math.arcsin -define dllexport double @__quantum__qis__arcsin__body(double %theta) { ; https://en.cppreference.com/w/cpp/numeric/math/asin - %result = call double @quantum__qis__arcsin__body(double %theta) - ret double %result -} - -; function ArcCos (theta : Double) : Double -; https://docs.microsoft.com/qsharp/api/qsharp/microsoft.quantum.math.arccos -define dllexport double @__quantum__qis__arccos__body(double %theta) { ; https://en.cppreference.com/w/cpp/numeric/math/acos - %result = call double @quantum__qis__arccos__body(double %theta) - ret double %result -} - -; function ArcTan (theta : Double) : Double -; https://docs.microsoft.com/qsharp/api/qsharp/microsoft.quantum.math.arctan -define dllexport double @__quantum__qis__arctan__body(double %theta) { ; https://en.cppreference.com/w/cpp/numeric/math/atan - %result = call double @quantum__qis__arctan__body(double %theta) - ret double %result -} - - -; function IEEERemainder(x : Double, y : Double) : Double -define dllexport double @__quantum__qis__ieeeremainder__body(double %x, double %y) { - %result = call double @quantum__qis__ieeeremainder__body(double %x, double %y) - ret double %result -} - - -; operation DrawRandomInt (min : Int, max : Int) : Int -; https://docs.microsoft.com/qsharp/api/qsharp/microsoft.quantum.random.drawrandomint -define dllexport i64 @__quantum__qis__drawrandomint__body(i64 %min, i64 %max) { - %result = call 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/operations implementation -; -define dllexport void @__quantum__qis__applyifelseintrinsic__body( - %Result* %.r, %Callable* %.clb_on_zero, %Callable* %.clb_on_one) { - - %r = bitcast %Result* %.r to %class.RESULT* - %clb_on_zero = bitcast %Callable* %.clb_on_zero to %struct.QirCallable* - %clb_on_one = bitcast %Callable* %.clb_on_one to %struct.QirCallable* - call void @quantum__qis__applyifelseintrinsic__body( - %class.RESULT* %r, %struct.QirCallable* %clb_on_zero, %struct.QirCallable* %clb_on_one) - ret void -} - -define dllexport void @__quantum__qis__applyconditionallyintrinsic__body( - %Array* %.rs1, %Array* %.rs2, %Callable* %.clb_on_equal, %Callable* %.clb_on_different) { - - %rs1 = bitcast %Array* %.rs1 to %struct.QirArray* - %rs2 = bitcast %Array* %.rs2 to %struct.QirArray* - %clb_on_equal = bitcast %Callable* %.clb_on_equal to %struct.QirCallable* - %clb_on_different = bitcast %Callable* %.clb_on_different to %struct.QirCallable* - call void @quantum__qis__applyconditionallyintrinsic__body( - %struct.QirArray* %rs1, %struct.QirArray* %rs2, - %struct.QirCallable* %clb_on_equal, %struct.QirCallable* %clb_on_different) - ret void -} - -;=============================================================================== -; quantum.qis AssertMeasurementProbability functions/operations implementation -; -define dllexport void @__quantum__qis__assertmeasurementprobability__body( - %Array* %.bases, %Array* %.qubits, %Result* %.result, double %prob, %String* %.msg, double %tol) { - - %bases = bitcast %Array* %.bases to %struct.QirArray* - %qubits = bitcast %Array* %.qubits to %struct.QirArray* - %result = bitcast %Result* %.result to %class.RESULT* - %msg = bitcast %String* %.msg to %struct.QirString* - - call void @quantum__qis__assertmeasurementprobability__body( - %struct.QirArray* %bases, %struct.QirArray* %qubits, %class.RESULT* %result, double %prob, %struct.QirString* %msg, double %tol) - - ret void -} - -define dllexport void @__quantum__qis__assertmeasurementprobability__adj( - %Array* %.bases, %Array* %.qubits, %Result* %.result, double %prob, %String* %.msg, double %tol) { - ; Empty. - ret void -} - -define dllexport void @__quantum__qis__assertmeasurementprobability__ctl( - %Array* %.ctrlQubits, - %Array* %.bases, %Array* %.qubits, %Result* %.result, double %prob, %String* %.msg, double %tol) { - ; Empty. - ret void -} - -define dllexport void @__quantum__qis__assertmeasurementprobability__ctladj( - %Array* %.ctrlQubits, - %Array* %.bases, %Array* %.qubits, %Result* %.result, double %prob, %String* %.msg, double %tol) { - ; Empty. - ret void -} diff --git a/src/Qir/Runtime/lib/QSharpFoundation/qsharp__foundation__qis.hpp b/src/Qir/Runtime/lib/QSharpFoundation/qsharp__foundation__qis.hpp index d3510502792..9148ff5222d 100644 --- a/src/Qir/Runtime/lib/QSharpFoundation/qsharp__foundation__qis.hpp +++ b/src/Qir/Runtime/lib/QSharpFoundation/qsharp__foundation__qis.hpp @@ -11,6 +11,16 @@ struct QirArray; struct QirCallable; +struct QirAssertMeasurementProbabilityTuple +{ + QirArray* bases; + QirArray* qubits; + RESULT* result; + double prob; + QirString* msg; + double tol; +}; + /* Methods from __quantum__qis namespace are specific to the target. When QIR is generated it might limit or extend the set of intrinsics, supported by the target (known to QIR generator at compile time). As part of the runtime @@ -19,27 +29,37 @@ struct QirCallable; extern "C" { // Q# Math: - QIR_SHARED_API bool quantum__qis__isnan__body(double d); // NOLINT - QIR_SHARED_API double quantum__qis__infinity__body(); // NOLINT - QIR_SHARED_API bool quantum__qis__isinf__body(double d); // NOLINT - QIR_SHARED_API double quantum__qis__arctan2__body(double y, double x); // NOLINT - QIR_SHARED_API double quantum__qis__sinh__body(double theta); // NOLINT - QIR_SHARED_API double quantum__qis__cosh__body(double theta); // NOLINT - QIR_SHARED_API double quantum__qis__arcsin__body(double theta); // NOLINT - QIR_SHARED_API double quantum__qis__arccos__body(double theta); // NOLINT - QIR_SHARED_API double quantum__qis__arctan__body(double theta); // NOLINT - - 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 + QIR_SHARED_API double __quantum__qis__nan__body(); // NOLINT + QIR_SHARED_API bool __quantum__qis__isnan__body(double d); // NOLINT + QIR_SHARED_API double __quantum__qis__infinity__body(); // NOLINT + QIR_SHARED_API bool __quantum__qis__isinf__body(double d); // NOLINT + QIR_SHARED_API bool __quantum__qis__isnegativeinfinity__body(double d); // NOLINT + QIR_SHARED_API double __quantum__qis__sin__body(double d); // NOLINT + QIR_SHARED_API double __quantum__qis__cos__body(double d); // NOLINT + QIR_SHARED_API double __quantum__qis__tan__body(double d); // NOLINT + QIR_SHARED_API double __quantum__qis__arctan2__body(double y, double x); // NOLINT + QIR_SHARED_API double __quantum__qis__sinh__body(double theta); // NOLINT + QIR_SHARED_API double __quantum__qis__cosh__body(double theta); // NOLINT + QIR_SHARED_API double __quantum__qis__tanh__body(double theta); // NOLINT + QIR_SHARED_API double __quantum__qis__arcsin__body(double theta); // NOLINT + QIR_SHARED_API double __quantum__qis__arccos__body(double theta); // NOLINT + QIR_SHARED_API double __quantum__qis__arctan__body(double theta); // NOLINT + QIR_SHARED_API double __quantum__qis__sqrt__body(double d); // NOLINT + QIR_SHARED_API double __quantum__qis__log__body(double d); // NOLINT + + 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 - QIR_SHARED_API void quantum__qis__applyconditionallyintrinsic__body( // NOLINT + QIR_SHARED_API void __quantum__qis__applyifelseintrinsic__body(RESULT*, QirCallable*, QirCallable*); // NOLINT + QIR_SHARED_API void __quantum__qis__applyconditionallyintrinsic__body( // NOLINT QirArray*, QirArray*, QirCallable*, QirCallable*); // Q# Assert Measurement: - QIR_SHARED_API void quantum__qis__assertmeasurementprobability__body( // NOLINT + QIR_SHARED_API void __quantum__qis__assertmeasurementprobability__body( // NOLINT QirArray* bases, QirArray* qubits, RESULT* result, double prob, QirString* msg, double tol); + QIR_SHARED_API void __quantum__qis__assertmeasurementprobability__ctl( // NOLINT + QirArray* ctls, QirAssertMeasurementProbabilityTuple* args); } // extern "C" diff --git a/src/Qir/Runtime/lib/Simulators/FullstateSimulator.cpp b/src/Qir/Runtime/lib/Simulators/FullstateSimulator.cpp index 61797ceb832..928c72a73ea 100644 --- a/src/Qir/Runtime/lib/Simulators/FullstateSimulator.cpp +++ b/src/Qir/Runtime/lib/Simulators/FullstateSimulator.cpp @@ -91,6 +91,7 @@ namespace Quantum // TODO: is it OK to load/unload the dll for each simulator instance? class CFullstateSimulator : public IRuntimeDriver + , public IRestrictedAreaManagement , public IQuantumGateSet , public IDiagnostics { @@ -112,6 +113,17 @@ namespace Quantum return static_cast(pauli); } + std::vector GetBases(long num, PauliId* paulis) + { + std::vector convertedBases; + convertedBases.reserve((size_t)num); + for (auto i = 0; i < num; i++) + { + convertedBases.push_back(GetBasis(paulis[i])); + } + return convertedBases; + } + const QUANTUM_SIMULATOR handle = nullptr; using TSimulatorId = unsigned; // TODO: Use `void*` or a fixed-size integer, @@ -253,11 +265,27 @@ namespace Quantum // We reject the release of a qubit that is not in the ground state (releaseQubit returns false), // and was not recently measured (ie: the last operation was not measurement). This means the // state is not well known, and therefore the safety of release is not guaranteed. - quantum__rt__fail_cstr("Released qubit neither measured nor in ground state."); + __quantum__rt__fail_cstr("Released qubit neither measured nor in ground state."); } qubitManager->Release(q); // Release it in the qubit manager. } + // IRestrictedAreaManagement + + virtual void StartArea() override + { + qubitManager->StartRestrictedReuseArea(); + } + + virtual void NextSegment() override + { + qubitManager->NextRestrictedReuseSegment(); + } + virtual void EndArea() override + { + qubitManager->EndRestrictedReuseArea(); + } + Result Measure(long numBases, PauliId bases[], long numTargets, Qubit targets[]) override { assert(numBases == numTargets); @@ -269,8 +297,10 @@ namespace Quantum // If measuring exactly one qubit, mark it as measured for tracking. isMeasured[ids[0]] = true; } + std::vector convertedBases = GetBases(numBases, bases); + return reinterpret_cast( - m(this->simulatorId, (unsigned)numBases, reinterpret_cast(bases), ids.data())); + m(this->simulatorId, (unsigned)numBases, convertedBases.data(), ids.data())); } void ReleaseResult(Result /*r*/) override @@ -452,9 +482,10 @@ namespace Quantum void Exp(long numTargets, PauliId paulis[], Qubit targets[], double theta) override { typedef unsigned (*TExp)(unsigned, unsigned, unsigned*, double, unsigned*); - static TExp exp = reinterpret_cast(this->GetProc("Exp")); - std::vector ids = GetQubitIds(numTargets, targets); - exp(this->simulatorId, (unsigned)numTargets, reinterpret_cast(paulis), theta, ids.data()); + static TExp exp = reinterpret_cast(this->GetProc("Exp")); + std::vector ids = GetQubitIds(numTargets, targets); + std::vector convertedBases = GetBases(numTargets, paulis); + exp(this->simulatorId, (unsigned)numTargets, convertedBases.data(), theta, ids.data()); UnmarkAsMeasuredQubitList(numTargets, targets); } @@ -462,11 +493,12 @@ namespace Quantum double theta) override { typedef unsigned (*TMCExp)(unsigned, unsigned, unsigned*, double, unsigned, unsigned*, unsigned*); - static TMCExp cexp = reinterpret_cast(this->GetProc("MCExp")); - std::vector idsTargets = GetQubitIds(numTargets, targets); - std::vector idsControls = GetQubitIds(numControls, controls); - cexp(this->simulatorId, (unsigned)numTargets, reinterpret_cast(paulis), theta, - (unsigned)numControls, idsControls.data(), idsTargets.data()); + static TMCExp cexp = reinterpret_cast(this->GetProc("MCExp")); + std::vector idsTargets = GetQubitIds(numTargets, targets); + std::vector idsControls = GetQubitIds(numControls, controls); + std::vector convertedBases = GetBases(numTargets, paulis); + cexp(this->simulatorId, (unsigned)numTargets, convertedBases.data(), theta, (unsigned)numControls, + idsControls.data(), idsTargets.data()); UnmarkAsMeasuredQubitList(numTargets, targets); UnmarkAsMeasuredQubitList(numControls, controls); } @@ -483,9 +515,11 @@ namespace Quantum typedef double (*TOp)(unsigned id, unsigned n, int* b, unsigned* q); static TOp jointEnsembleProbability = reinterpret_cast(this->GetProc("JointEnsembleProbability")); - std::vector ids = GetQubitIds(numTargets, targets); - double actualProbability = 1.0 - jointEnsembleProbability(this->simulatorId, (unsigned)numTargets, - reinterpret_cast(bases), ids.data()); + std::vector ids = GetQubitIds(numTargets, targets); + std::vector convertedBases = GetBases(numTargets, bases); + double actualProbability = + 1.0 - jointEnsembleProbability(this->simulatorId, (unsigned)numTargets, + reinterpret_cast(convertedBases.data()), ids.data()); return (std::abs(actualProbability - probabilityOfZero) < precision); } diff --git a/src/Qir/Runtime/lib/Tracer/CMakeLists.txt b/src/Qir/Runtime/lib/Tracer/CMakeLists.txt index a73cfeb28fd..8ef274e87ef 100644 --- a/src/Qir/Runtime/lib/Tracer/CMakeLists.txt +++ b/src/Qir/Runtime/lib/Tracer/CMakeLists.txt @@ -11,7 +11,6 @@ set(includes # 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(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) diff --git a/src/Qir/Runtime/lib/Tracer/tracer-bridge.ll b/src/Qir/Runtime/lib/Tracer/tracer-bridge.ll deleted file mode 100644 index 22d39a98a5e..00000000000 --- a/src/Qir/Runtime/lib/Tracer/tracer-bridge.ll +++ /dev/null @@ -1,102 +0,0 @@ -; Copyright (c) Microsoft Corporation. -; Licensed under the MIT License. - -;======================================================================================================================= -; QIR types -; -%Array = type opaque -%Callable = type opaque -%Qubit = type opaque -%Result = type opaque - - -;======================================================================================================================= -; Native types -; -%class.QUBIT = type opaque -%class.RESULT = type opaque -%struct.QirArray = type opaque -%struct.QirCallable = type opaque - - -;=============================================================================== -; declarations of the native methods this bridge delegates to -; - -declare void @quantum__qis__single_qubit_op(i32 %id, i32 %duration, %class.QUBIT*) -declare void @quantum__qis__single_qubit_op_ctl(i32 %id, i32 %duration, %struct.QirArray*, %class.QUBIT*) -declare void @quantum__qis__multi_qubit_op(i32 %id, i32 %duration, %struct.QirArray*) -declare void @quantum__qis__multi_qubit_op_ctl(i32 %id, i32 %duration, %struct.QirArray*, %struct.QirArray*) -declare void @quantum__qis__inject_barrier(i32 %id, i32 %duration) -declare %class.RESULT* @quantum__qis__single_qubit_measure(i32 %id, i32 %duration, %class.QUBIT*) -declare %class.RESULT* @quantum__qis__joint_measure(i32 %id, i32 %duration, %struct.QirArray*) -declare void @quantum__qis__apply_conditionally( - %struct.QirArray*, %struct.QirArray*, %struct.QirCallable*, %struct.QirCallable*) - -;=============================================================================== -; quantum__trc namespace implementations -; -define dllexport void @__quantum__qis__single_qubit_op(i32 %id, i32 %duration, %Qubit* %.q) -{ - %q = bitcast %Qubit* %.q to %class.QUBIT* - call void @quantum__qis__single_qubit_op(i32 %id, i32 %duration, %class.QUBIT* %q) - ret void -} - -define dllexport void @__quantum__qis__single_qubit_op_ctl(i32 %id, i32 %duration, %Array* %.ctls, %Qubit* %.q) -{ - %q = bitcast %Qubit* %.q to %class.QUBIT* - %ctls = bitcast %Array* %.ctls to %struct.QirArray* - call void @quantum__qis__single_qubit_op_ctl(i32 %id, i32 %duration, %struct.QirArray* %ctls, %class.QUBIT* %q) - ret void -} - -define dllexport void @__quantum__qis__multi_qubit_op(i32 %id, i32 %duration, %Array* %.qs) -{ - %qs = bitcast %Array* %.qs to %struct.QirArray* - call void @quantum__qis__multi_qubit_op(i32 %id, i32 %duration, %struct.QirArray* %qs) - ret void -} - -define dllexport void @__quantum__qis__multi_qubit_op_ctl(i32 %id, i32 %duration, %Array* %.ctls, %Array* %.qs) -{ - %ctls = bitcast %Array* %.ctls to %struct.QirArray* - %qs = bitcast %Array* %.qs to %struct.QirArray* - call void @quantum__qis__multi_qubit_op_ctl(i32 %id, i32 %duration, %struct.QirArray* %ctls, %struct.QirArray* %qs) - ret void -} - -define dllexport void @__quantum__qis__inject_barrier(i32 %id, i32 %duration) -{ - call void @quantum__qis__inject_barrier(i32 %id, i32 %duration) - ret void -} - -define dllexport %Result* @__quantum__qis__single_qubit_measure(i32 %id, i32 %duration, %Qubit* %.q) -{ - %q = bitcast %Qubit* %.q to %class.QUBIT* - %r = call %class.RESULT* @quantum__qis__single_qubit_measure(i32 %id, i32 %duration, %class.QUBIT* %q) - %.r = bitcast %class.RESULT* %r to %Result* - ret %Result* %.r -} - -define dllexport %Result* @__quantum__qis__joint_measure(i32 %id, i32 %duration, %Array* %.qs) -{ - %qs = bitcast %Array* %.qs to %struct.QirArray* - %r = call %class.RESULT* @quantum__qis__joint_measure(i32 %id, i32 %duration, %struct.QirArray* %qs) - %.r = bitcast %class.RESULT* %r to %Result* - ret %Result* %.r -} - -define dllexport void @__quantum__qis__apply_conditionally( - %Array* %.rs1, %Array* %.rs2, %Callable* %.clb_on_equal, %Callable* %.clb_on_different) { - - %rs1 = bitcast %Array* %.rs1 to %struct.QirArray* - %rs2 = bitcast %Array* %.rs2 to %struct.QirArray* - %clb_on_equal = bitcast %Callable* %.clb_on_equal to %struct.QirCallable* - %clb_on_different = bitcast %Callable* %.clb_on_different to %struct.QirCallable* - call void @quantum__qis__apply_conditionally( - %struct.QirArray* %rs1, %struct.QirArray* %rs2, - %struct.QirCallable* %clb_on_equal, %struct.QirCallable* %clb_on_different) - ret void -} \ No newline at end of file diff --git a/src/Qir/Runtime/lib/Tracer/tracer-qis.cpp b/src/Qir/Runtime/lib/Tracer/tracer-qis.cpp index 13c5eb04d97..251effd6719 100644 --- a/src/Qir/Runtime/lib/Tracer/tracer-qis.cpp +++ b/src/Qir/Runtime/lib/Tracer/tracer-qis.cpp @@ -13,54 +13,54 @@ using namespace Microsoft::Quantum; extern "C" { - void quantum__qis__on_operation_start(int64_t /* id */) // NOLINT + void __quantum__qis__on_operation_start(int64_t /* id */) // NOLINT { } - void quantum__qis__on_operation_end(int64_t /* id */) // NOLINT + void __quantum__qis__on_operation_end(int64_t /* id */) // NOLINT { } - void quantum__qis__swap(Qubit /*q1*/, Qubit /*q2*/) // NOLINT + void __quantum__qis__swap(Qubit /*q1*/, Qubit /*q2*/) // NOLINT { } - void quantum__qis__single_qubit_op(int32_t id, int32_t duration, Qubit target) // NOLINT + void __quantum__qis__single_qubit_op(int32_t id, int32_t duration, Qubit target) // NOLINT { (void)tracer->TraceSingleQubitOp(id, duration, target); } - void quantum__qis__single_qubit_op_ctl(int32_t id, int32_t duration, QirArray* ctls, Qubit target) // NOLINT + void __quantum__qis__single_qubit_op_ctl(int32_t id, int32_t duration, QirArray* ctls, Qubit target) // NOLINT { (void)tracer->TraceMultiQubitOp(id, duration, (long)(ctls->count), reinterpret_cast(ctls->buffer), 1, &target); } - void quantum__qis__multi_qubit_op(int32_t id, int32_t duration, QirArray* targets) // NOLINT + void __quantum__qis__multi_qubit_op(int32_t id, int32_t duration, QirArray* targets) // NOLINT { (void)tracer->TraceMultiQubitOp(id, duration, 0, nullptr, (long)(targets->count), reinterpret_cast(targets->buffer)); } - void quantum__qis__multi_qubit_op_ctl(int32_t id, int32_t duration, QirArray* ctls, QirArray* targets) // NOLINT + void __quantum__qis__multi_qubit_op_ctl(int32_t id, int32_t duration, QirArray* ctls, QirArray* targets) // NOLINT { (void)tracer->TraceMultiQubitOp(id, duration, (long)(ctls->count), reinterpret_cast(ctls->buffer), (long)(targets->count), reinterpret_cast(targets->buffer)); } - void quantum__qis__inject_barrier(int32_t id, int32_t duration) // NOLINT + void __quantum__qis__inject_barrier(int32_t id, int32_t duration) // NOLINT { (void)tracer->InjectGlobalBarrier(id, duration); } - RESULT* quantum__qis__single_qubit_measure(int32_t id, int32_t duration, QUBIT* q) // NOLINT + RESULT* __quantum__qis__single_qubit_measure(int32_t id, int32_t duration, QUBIT* q) // NOLINT { return tracer->TraceSingleQubitMeasurement(id, duration, q); } - RESULT* quantum__qis__joint_measure(int32_t id, int32_t duration, QirArray* qs) // NOLINT + RESULT* __quantum__qis__joint_measure(int32_t id, int32_t duration, QirArray* qs) // NOLINT { return tracer->TraceMultiQubitMeasurement(id, duration, (long)(qs->count), reinterpret_cast(qs->buffer)); } - void quantum__qis__apply_conditionally( // NOLINT + void __quantum__qis__apply_conditionally( // NOLINT QirArray* rs1, QirArray* rs2, QirCallable* clbOnAllEqual, QirCallable* clbOnSomeDifferent) { CTracer::FenceScope sf(tracer.get(), (long)(rs1->count), reinterpret_cast(rs1->buffer), diff --git a/src/Qir/Runtime/lib/Tracer/tracer-qis.hpp b/src/Qir/Runtime/lib/Tracer/tracer-qis.hpp index b212a9fad61..db475f8635c 100644 --- a/src/Qir/Runtime/lib/Tracer/tracer-qis.hpp +++ b/src/Qir/Runtime/lib/Tracer/tracer-qis.hpp @@ -9,21 +9,23 @@ extern "C" { - void quantum__qis__on_operation_start(int64_t /* id */); // NOLINT - void quantum__qis__on_operation_end(int64_t /* id */); // NOLINT - void quantum__qis__swap(Qubit /*q1*/, Qubit /*q2*/); // NOLINT + QIR_SHARED_API void __quantum__qis__on_operation_start(int64_t /* id */); // NOLINT + QIR_SHARED_API void __quantum__qis__on_operation_end(int64_t /* id */); // NOLINT + QIR_SHARED_API void __quantum__qis__swap(Qubit /*q1*/, Qubit /*q2*/); // NOLINT - void quantum__qis__single_qubit_op(int32_t id, int32_t duration, Qubit target); // NOLINT - void quantum__qis__single_qubit_op_ctl(int32_t id, int32_t duration, QirArray* ctls, Qubit target); // NOLINT - void quantum__qis__multi_qubit_op(int32_t id, int32_t duration, QirArray* targets); // NOLINT - void quantum__qis__multi_qubit_op_ctl(int32_t id, int32_t duration, QirArray* ctls, QirArray* targets); // NOLINT + QIR_SHARED_API void __quantum__qis__single_qubit_op(int32_t id, int32_t duration, Qubit target); // NOLINT + QIR_SHARED_API void __quantum__qis__single_qubit_op_ctl( // NOLINT + int32_t id, int32_t duration, QirArray* ctls, Qubit target); + QIR_SHARED_API void __quantum__qis__multi_qubit_op(int32_t id, int32_t duration, QirArray* targets); // NOLINT + QIR_SHARED_API void __quantum__qis__multi_qubit_op_ctl( // NOLINT + int32_t id, int32_t duration, QirArray* ctls, QirArray* targets); - void quantum__qis__inject_barrier(int32_t id, int32_t duration); // NOLINT - RESULT* quantum__qis__single_qubit_measure(int32_t id, int32_t duration, QUBIT* q); // NOLINT + QIR_SHARED_API void __quantum__qis__inject_barrier(int32_t id, int32_t duration); // NOLINT + QIR_SHARED_API RESULT* __quantum__qis__single_qubit_measure(int32_t id, int32_t duration, QUBIT* q); // NOLINT - RESULT* quantum__qis__joint_measure(int32_t id, int32_t duration, QirArray* qs); // NOLINT + QIR_SHARED_API RESULT* __quantum__qis__joint_measure(int32_t id, int32_t duration, QirArray* qs); // NOLINT - void quantum__qis__apply_conditionally( // NOLINT + QIR_SHARED_API void __quantum__qis__apply_conditionally( // NOLINT QirArray* rs1, QirArray* rs2, QirCallable* clbOnAllEqual, QirCallable* clbOnSomeDifferent); } // extern "C" diff --git a/src/Qir/Runtime/prerequisites.ps1 b/src/Qir/Runtime/prerequisites.ps1 index 6d90aacf3a4..74b9607269d 100644 --- a/src/Qir/Runtime/prerequisites.ps1 +++ b/src/Qir/Runtime/prerequisites.ps1 @@ -4,7 +4,7 @@ #Requires -Version 6.0 if ($Env:ENABLE_QIRRUNTIME -ne "false") { - if (($IsWindows) -or ((Test-Path Env:AGENT_OS) -and ($Env:AGENT_OS.StartsWith("Win")))) { + if (($IsWindows) -or ((Test-Path Env:/AGENT_OS) -and ($Env:AGENT_OS.StartsWith("Win")))) { if (!(Get-Command clang -ErrorAction SilentlyContinue) -or ` !(Get-Command clang-format -ErrorAction SilentlyContinue)) { choco install llvm --version=11.1.0 @@ -29,10 +29,10 @@ if ($Env:ENABLE_QIRRUNTIME -ne "false") { } else { if (Get-Command sudo -ErrorAction SilentlyContinue) { sudo apt update - sudo apt-get install -y ninja-build clang-11 clang-tidy-11 + sudo apt-get install -y ninja-build clang-11 clang-tidy-11 clang-format-11 } else { apt update - apt-get install -y ninja-build clang-11 clang-tidy-11 + apt-get install -y ninja-build clang-11 clang-tidy-11 clang-format-11 } } } diff --git a/src/Qir/Runtime/public/CoreTypes.hpp b/src/Qir/Runtime/public/CoreTypes.hpp index 37bb6d95850..d0817b41beb 100644 --- a/src/Qir/Runtime/public/CoreTypes.hpp +++ b/src/Qir/Runtime/public/CoreTypes.hpp @@ -36,7 +36,7 @@ class QUBIT; typedef QUBIT* Qubit; // Not a pointer to a memory location, just an integer - qubit id. class RESULT; -typedef RESULT* Result; // TODO: Replace with `typedef uintXX_t Result`, where XX is 8|16|32|64. +typedef RESULT* Result; // TODO(rokuzmin): Replace with `typedef uintXX_t Result`, where XX is 8|16|32|64. // Remove all the `RESULT`. enum ResultValue @@ -49,7 +49,7 @@ enum ResultValue /*============================================================================== PauliId matrices ==============================================================================*/ -enum PauliId : int32_t +enum PauliId : int8_t { PauliId_I = 0, PauliId_X = 1, diff --git a/src/Qir/Runtime/public/OutputStream.hpp b/src/Qir/Runtime/public/OutputStream.hpp index 06ca71118ac..76a2547f170 100644 --- a/src/Qir/Runtime/public/OutputStream.hpp +++ b/src/Qir/Runtime/public/OutputStream.hpp @@ -15,9 +15,15 @@ namespace Quantum { struct QIR_SHARED_API ScopedRedirector { - ScopedRedirector(std::ostream& newOstream); + explicit ScopedRedirector(std::ostream& newOstream); ~ScopedRedirector(); + private: + ScopedRedirector(const ScopedRedirector&) = delete; + ScopedRedirector& operator=(const ScopedRedirector&) = delete; + ScopedRedirector(ScopedRedirector&&) = delete; + ScopedRedirector& operator=(ScopedRedirector&&) = delete; + private: std::ostream& old; }; diff --git a/src/Qir/Runtime/public/QirRuntime.hpp b/src/Qir/Runtime/public/QirRuntime.hpp index d33dcec1d7d..36c17e74d89 100644 --- a/src/Qir/Runtime/public/QirRuntime.hpp +++ b/src/Qir/Runtime/public/QirRuntime.hpp @@ -4,7 +4,7 @@ #pragma once #include -#include // for va_list +#include // for va_list #include "CoreTypes.hpp" #include "QirTypes.hpp" @@ -12,83 +12,101 @@ extern "C" { // ------------------------------------------------------------------------ - // Qubits + // Qubit Management. // ------------------------------------------------------------------------ - // Allocates a single qubit. - QIR_SHARED_API QUBIT* quantum__rt__qubit_allocate(); // NOLINT + // Allocate one qubit. Qubit is guaranteed to be in |0> state. + // Qubit needs to be released via __quantum__rt__qubit_release. + QIR_SHARED_API QUBIT* __quantum__rt__qubit_allocate(); // NOLINT - // Allocates an array of qubits. - QIR_SHARED_API QirArray* quantum__rt__qubit_allocate_array(int64_t count); // NOLINT + // Allocate 'count' qubits, allocate and return an array that owns these qubits. + // Array and qubits in the array need to be released via __quantum__rt__qubit_release_array. + QIR_SHARED_API QirArray* __quantum__rt__qubit_allocate_array(int64_t count); // NOLINT - // Release a single qubit. - QIR_SHARED_API void quantum__rt__qubit_release(QUBIT*); // NOLINT + // Release one qubit. + QIR_SHARED_API void __quantum__rt__qubit_release(QUBIT*); // NOLINT - // Release qubits, owned by the array. The array itself is also released. - QIR_SHARED_API void quantum__rt__qubit_release_array(QirArray*); // NOLINT + // Release qubits, owned by the array and the array itself. + QIR_SHARED_API void __quantum__rt__qubit_release_array(QirArray*); // NOLINT - // Borrow a single qubit. - // TODO QIR_SHARED_API QUBIT* quantum__rt__qubit_borrow(); // NOLINT + // Borrow one qubit. Qubit is not guaranteed to be in |0> state. + // Qubit needs to be returned via __quantum__rt__qubit_return in the same state in which it was borrowed. + QIR_SHARED_API QUBIT* __quantum__rt__qubit_borrow(); // NOLINT - // Borrow an array of qubits. - // TODO QIR_SHARED_API QirArray* quantum__rt__qubit_borrow_array(int64_t count); // NOLINT + // Borrow 'count' qubits, allocate and return an array that owns these qubits. + // Array and qubits in the array need to be returned via __quantum__rt__qubit_return_array. + QIR_SHARED_API QirArray* __quantum__rt__qubit_borrow_array(int64_t count); // NOLINT - // Return a borrowed qubit. - // TODO QIR_SHARED_API void quantum__rt__qubit_return(QUBIT*); // NOLINT + // Return one borrowed qubit. Qubit must be in the same state in which it was borrowed. + QIR_SHARED_API void __quantum__rt__qubit_return(QUBIT*); // NOLINT - // Return an array of borrowed qubits. - // TODO QIR_SHARED_API void quantum__rt__qubit_return_array(QirArray*); // NOLINT + // Return borrowed qubits owned by the array. Release array itself. + QIR_SHARED_API void __quantum__rt__qubit_return_array(QirArray*); // NOLINT + + // ------------------------------------------------------------------------ + // Qubit Management Restricted Reuse Control. + // ------------------------------------------------------------------------ + + // Start restricted reuse area. + // Qubits released within one segment of an area cannot be reused in other segments of the same area. + QIR_SHARED_API void __quantum__rt__qubit_restricted_reuse_area_start(); // NOLINT + + // End current restricted reuse segment and start the next one within the current area. + QIR_SHARED_API void __quantum__rt__qubit_restricted_reuse_segment_next(); // NOLINT + + // End current restricted reuse area. + QIR_SHARED_API void __quantum__rt__qubit_restricted_reuse_area_end(); // NOLINT // ------------------------------------------------------------------------ // Utils // ------------------------------------------------------------------------ // Allocate a block of memory on the heap. - QIR_SHARED_API char* quantum__rt__heap_alloc(uint64_t 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 + 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 + QIR_SHARED_API char* __quantum__rt__memory_allocate(uint64_t size); // NOLINT // Fail the computation with the given error message. - [[noreturn]] QIR_SHARED_API void quantum__rt__fail(QirString* msg); // NOLINT - [[noreturn]] QIR_SHARED_API void quantum__rt__fail_cstr(const char* msg); // NOLINT + [[noreturn]] QIR_SHARED_API void __quantum__rt__fail(QirString* msg); // NOLINT + [[noreturn]] QIR_SHARED_API void __quantum__rt__fail_cstr(const char* msg); // NOLINT // Include the given message in the computation's execution log or equivalent. - QIR_SHARED_API void quantum__rt__message(QirString* msg); // NOLINT + QIR_SHARED_API void __quantum__rt__message(QirString* msg); // NOLINT // ------------------------------------------------------------------------ // Results // ------------------------------------------------------------------------ // Returns true if the two results are the same, and false if they are different. - QIR_SHARED_API bool quantum__rt__result_equal(RESULT*, RESULT*); // NOLINT + QIR_SHARED_API bool __quantum__rt__result_equal(RESULT*, RESULT*); // NOLINT // Adds the given integer value to the reference count for the result. Deallocates the result if the reference count // 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 + QIR_SHARED_API void __quantum__rt__result_update_reference_count(RESULT*, int32_t); // NOLINT - QIR_SHARED_API RESULT* quantum__rt__result_get_one(); // NOLINT - QIR_SHARED_API RESULT* quantum__rt__result_get_zero(); // NOLINT + QIR_SHARED_API RESULT* __quantum__rt__result_get_one(); // NOLINT + QIR_SHARED_API RESULT* __quantum__rt__result_get_zero(); // NOLINT // ------------------------------------------------------------------------ // Tuples // ------------------------------------------------------------------------ // Allocates space for a tuple requiring the given number of bytes and sets the reference count to 1. - QIR_SHARED_API PTuple quantum__rt__tuple_create(int64_t); // NOLINT + QIR_SHARED_API PTuple __quantum__rt__tuple_create(int64_t); // NOLINT // Adds the given integer value to the reference count for the tuple. Deallocates the tuple if the reference count // becomes 0. The behavior is undefined if the reference count becomes negative. - QIR_SHARED_API void quantum__rt__tuple_update_reference_count(PTuple, int32_t); // NOLINT + QIR_SHARED_API void __quantum__rt__tuple_update_reference_count(PTuple, int32_t); // NOLINT // Adds the given integer value to the alias count for the tuple. Fails if the count becomes negative. - QIR_SHARED_API void quantum__rt__tuple_update_alias_count(PTuple, int32_t); // NOLINT + QIR_SHARED_API void __quantum__rt__tuple_update_alias_count(PTuple, int32_t); // NOLINT // Creates a shallow copy of the tuple if the user count is larger than 0 or the second argument is `true`. - QIR_SHARED_API PTuple quantum__rt__tuple_copy(PTuple, bool force); // NOLINT + QIR_SHARED_API PTuple __quantum__rt__tuple_copy(PTuple, bool force); // NOLINT // ------------------------------------------------------------------------ // Arrrays @@ -96,42 +114,43 @@ extern "C" // Creates a new 1-dimensional array. The int is the size of each element in bytes. The int64_t is the length // of the array. The bytes of the new array should be set to zero. - QIR_SHARED_API QirArray* quantum__rt__array_create_1d(int32_t, int64_t); // NOLINT + QIR_SHARED_API QirArray* __quantum__rt__array_create_1d(int32_t, int64_t); // NOLINT // Adds the given integer value to the reference count for the array. Deallocates the array if the reference count // becomes 0. The behavior is undefined if the reference count becomes negative. - QIR_SHARED_API void quantum__rt__array_update_reference_count(QirArray*, int32_t); // NOLINT + QIR_SHARED_API void __quantum__rt__array_update_reference_count(QirArray*, int32_t); // NOLINT // Adds the given integer value to the alias count for the array. Fails if the count becomes negative. - QIR_SHARED_API void quantum__rt__array_update_alias_count(QirArray*, int32_t); // NOLINT + QIR_SHARED_API void __quantum__rt__array_update_alias_count(QirArray*, int32_t); // NOLINT // Creates a shallow copy of the array if the user count is larger than 0 or the second argument is `true`. - QIR_SHARED_API QirArray* quantum__rt__array_copy(QirArray*, bool); // NOLINT + QIR_SHARED_API QirArray* __quantum__rt__array_copy(QirArray*, bool); // NOLINT // Returns a new array which is the concatenation of the two passed-in arrays. - QIR_SHARED_API QirArray* quantum__rt__array_concatenate(QirArray*, QirArray*); // NOLINT + QIR_SHARED_API QirArray* __quantum__rt__array_concatenate(QirArray*, QirArray*); // NOLINT // Returns the length of a dimension of the array. The int is the zero-based dimension to return the length of; it // must be 0 for a 1-dimensional array. - QIR_SHARED_API int64_t quantum__rt__array_get_size(QirArray*, int32_t); // NOLINT + QIR_SHARED_API int64_t __quantum__rt__array_get_size(QirArray*, int32_t); // NOLINT + QIR_SHARED_API int64_t __quantum__rt__array_get_size_1d(QirArray*); // NOLINT // Returns a pointer to the element of the array at the zero-based index given by the int64_t. - QIR_SHARED_API char* quantum__rt__array_get_element_ptr_1d(QirArray*, int64_t); // NOLINT + QIR_SHARED_API char* __quantum__rt__array_get_element_ptr_1d(QirArray*, int64_t); // NOLINT // Creates a new array. The first int is the size of each element in bytes. The second int is the dimension count. // The variable arguments should be a sequence of int64_ts contains the length of each dimension. The bytes of the // new array should be set to zero. - QIR_SHARED_API QirArray* quantum__rt__array_create(int, int, ...); // NOLINT - QIR_SHARED_API QirArray* quantum__rt__array_create_nonvariadic( // NOLINT + QIR_SHARED_API QirArray* __quantum__rt__array_create(int, int, ...); // NOLINT + QIR_SHARED_API QirArray* __quantum__rt__array_create_nonvariadic( // NOLINT int itemSizeInBytes, int countDimensions, va_list dims); // Returns the number of dimensions in the array. - QIR_SHARED_API int32_t quantum__rt__array_get_dim(QirArray*); // NOLINT + QIR_SHARED_API int32_t __quantum__rt__array_get_dim(QirArray*); // NOLINT // Returns a pointer to the indicated element of the array. The variable arguments should be a sequence of int64_ts // that are the indices for each dimension. - QIR_SHARED_API char* quantum__rt__array_get_element_ptr(QirArray*, ...); // NOLINT - QIR_SHARED_API char* quantum__rt__array_get_element_ptr_nonvariadic(QirArray*, va_list dims); // NOLINT + QIR_SHARED_API char* __quantum__rt__array_get_element_ptr(QirArray*, ...); // NOLINT + QIR_SHARED_API char* __quantum__rt__array_get_element_ptr_nonvariadic(QirArray*, va_list dims); // NOLINT // Creates and returns an array that is a slice of an existing array. The int indicates which dimension // the slice is on. The %Range specifies the slice. @@ -140,7 +159,7 @@ extern "C" // Creates and returns an array that is a projection of an existing array. The int indicates which dimension the // projection is on, and the int64_t specifies the specific index value to project. The returned Array* will have // one fewer dimension than the existing array. - QIR_SHARED_API QirArray* quantum__rt__array_project(QirArray*, int32_t, int64_t); // NOLINT + QIR_SHARED_API QirArray* __quantum__rt__array_project(QirArray*, int32_t, int64_t); // NOLINT // ------------------------------------------------------------------------ // Callables @@ -148,32 +167,33 @@ 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. - QIR_SHARED_API QirCallable* quantum__rt__callable_create(t_CallableEntry*, t_CaptureCallback*, PTuple); // 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 // count becomes 0. The behavior is undefined if the reference count becomes negative. - QIR_SHARED_API void quantum__rt__callable_update_reference_count(QirCallable*, int32_t); // NOLINT + QIR_SHARED_API void __quantum__rt__callable_update_reference_count(QirCallable*, int32_t); // NOLINT // Adds the given integer value to the alias count for the callable. Fails if the count becomes negative. - QIR_SHARED_API void quantum__rt__callable_update_alias_count(QirCallable*, int32_t); // NOLINT + QIR_SHARED_API void __quantum__rt__callable_update_alias_count(QirCallable*, int32_t); // NOLINT // Creates a shallow copy of the callable if the alias count is larger than 0 or the second argument is `true`. // Returns the given callable pointer otherwise, after increasing its reference count by 1. - QIR_SHARED_API QirCallable* quantum__rt__callable_copy(QirCallable*, bool); // NOLINT + QIR_SHARED_API QirCallable* __quantum__rt__callable_copy(QirCallable*, bool); // NOLINT // Invokes the callable with the provided argument tuple and fills in the result tuple. - QIR_SHARED_API void quantum__rt__callable_invoke(QirCallable*, PTuple, PTuple); // NOLINT + QIR_SHARED_API void __quantum__rt__callable_invoke(QirCallable*, PTuple, PTuple); // NOLINT // Updates the callable by applying the Adjoint functor. - QIR_SHARED_API void quantum__rt__callable_make_adjoint(QirCallable*); // NOLINT + QIR_SHARED_API void __quantum__rt__callable_make_adjoint(QirCallable*); // NOLINT // Updates the callable by applying the Controlled functor. - QIR_SHARED_API void quantum__rt__callable_make_controlled(QirCallable*); // NOLINT + 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 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*, int32_t); // NOLINT + // Invokes the function in the corresponding index in the memory management table of the callable with the capture + // tuple and 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__capture_update_reference_count(QirCallable*, int32_t); // NOLINT + QIR_SHARED_API void __quantum__rt__capture_update_alias_count(QirCallable*, int32_t); // NOLINT // ------------------------------------------------------------------------ // Strings @@ -181,116 +201,116 @@ extern "C" // Creates a string from an array of UTF-8 bytes. // TODO the provided constructor doesn't match the spec! - // QIR_SHARED_API QirString* quantum__rt__string_create(int, char*); // NOLINT - QIR_SHARED_API QirString* quantum__rt__string_create(const char*); // NOLINT + // QIR_SHARED_API QirString* __quantum__rt__string_create(int, char*); // NOLINT + QIR_SHARED_API QirString* __quantum__rt__string_create(const char*); // NOLINT // Adds the given integer value to the reference count for the string. Deallocates the string if the reference count // becomes 0. The behavior is undefined if the reference count becomes negative. - QIR_SHARED_API void quantum__rt__string_update_reference_count(QirString*, int32_t); // NOLINT + QIR_SHARED_API void __quantum__rt__string_update_reference_count(QirString*, int32_t); // NOLINT // Creates a new string that is the concatenation of the two argument strings. - QIR_SHARED_API QirString* quantum__rt__string_concatenate(QirString*, QirString*); // NOLINT + QIR_SHARED_API QirString* __quantum__rt__string_concatenate(QirString*, QirString*); // NOLINT // Returns true if the two strings are equal, false otherwise. - QIR_SHARED_API bool quantum__rt__string_equal(QirString*, QirString*); // NOLINT + QIR_SHARED_API bool __quantum__rt__string_equal(QirString*, QirString*); // NOLINT // Returns a string representation of the integer. - QIR_SHARED_API QirString* quantum__rt__int_to_string(int64_t); // NOLINT + QIR_SHARED_API QirString* __quantum__rt__int_to_string(int64_t); // NOLINT // Returns a string representation of the double. - QIR_SHARED_API QirString* quantum__rt__double_to_string(double); // NOLINT + QIR_SHARED_API QirString* __quantum__rt__double_to_string(double); // NOLINT // Returns a string representation of the Boolean. - QIR_SHARED_API QirString* quantum__rt__bool_to_string(bool); // NOLINT + QIR_SHARED_API QirString* __quantum__rt__bool_to_string(bool); // NOLINT // Returns a string representation of the result. - QIR_SHARED_API QirString* quantum__rt__result_to_string(RESULT*); // NOLINT + QIR_SHARED_API QirString* __quantum__rt__result_to_string(RESULT*); // NOLINT // Returns a string representation of the Pauli. - QIR_SHARED_API QirString* quantum__rt__pauli_to_string(PauliId); // NOLINT + QIR_SHARED_API QirString* __quantum__rt__pauli_to_string(PauliId); // NOLINT // Returns a string representation of the qubit. - QIR_SHARED_API QirString* quantum__rt__qubit_to_string(QUBIT*); // NOLINT + QIR_SHARED_API QirString* __quantum__rt__qubit_to_string(QUBIT*); // NOLINT // 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 + 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 + 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 + // TODO QIR_SHARED_API QirString* __quantum__rt__bigint_to_string(QirBigInt*); // NOLINT // ------------------------------------------------------------------------ // BigInts // ------------------------------------------------------------------------ // Creates a big integer with the specified initial value. - // TODO QIR_SHARED_API QirBigInt* quantum__rt__bigint_create_int64_t(int64_t); // NOLINT + // TODO QIR_SHARED_API QirBigInt* __quantum__rt__bigint_create_int64_t(int64_t); // NOLINT // Creates a big integer with the initial value specified by the i8 array. The 0-th element of the array is the // highest-order byte, followed by the first element, etc. - // TODO QIR_SHARED_API QirBigInt* quantum__rt__bigint_create_array(int, char*); // NOLINT + // TODO QIR_SHARED_API QirBigInt* __quantum__rt__bigint_create_array(int, char*); // NOLINT // Adds the given integer value to the reference count for the big integer. Deallocates the big integer if the // reference count becomes 0. The behavior is undefined if the reference count becomes negative. - // TODO QIR_SHARED_API void quantum__rt__bigint_update_reference_count(QirBigInt*, int32_t); // NOLINT + // TODO QIR_SHARED_API void __quantum__rt__bigint_update_reference_count(QirBigInt*, int32_t); // NOLINT // Returns the negative of the big integer. - // TODO QIR_SHARED_API QirBigInt* quantum__rt__bigint_negate(QirBigInt*); // NOLINT + // TODO QIR_SHARED_API QirBigInt* __quantum__rt__bigint_negate(QirBigInt*); // NOLINT // Adds two big integers and returns their sum. - // TODO QIR_SHARED_API QirBigInt* quantum__rt__bigint_add(QirBigInt*, QirBigInt*); // NOLINT + // TODO QIR_SHARED_API QirBigInt* __quantum__rt__bigint_add(QirBigInt*, QirBigInt*); // NOLINT // Subtracts the second big integer from the first and returns their difference. - // TODO QIR_SHARED_API QirBigInt* quantum__rt__bigint_subtract(QirBigInt*, QirBigInt*); // NOLINT + // TODO QIR_SHARED_API QirBigInt* __quantum__rt__bigint_subtract(QirBigInt*, QirBigInt*); // NOLINT // Multiplies two big integers and returns their product. - // TODO QIR_SHARED_API QirBigInt* quantum__rt__bigint_multiply(QirBigInt*, QirBigInt*); // NOLINT + // TODO QIR_SHARED_API QirBigInt* __quantum__rt__bigint_multiply(QirBigInt*, QirBigInt*); // NOLINT // Divides the first big integer by the second and returns their quotient. - // TODO QIR_SHARED_API QirBigInt* quantum__rt__bigint_divide(QirBigInt*, QirBigInt*); // NOLINT + // TODO QIR_SHARED_API QirBigInt* __quantum__rt__bigint_divide(QirBigInt*, QirBigInt*); // NOLINT // Returns the first big integer modulo the second. - // TODO QIR_SHARED_API QirBigInt* quantum__rt__bigint_modulus(QirBigInt*, QirBigInt*); // NOLINT + // TODO QIR_SHARED_API QirBigInt* __quantum__rt__bigint_modulus(QirBigInt*, QirBigInt*); // NOLINT // Returns the big integer raised to the integer power. - // TODO QIR_SHARED_API QirBigInt* quantum__rt__bigint_power(QirBigInt*, int); // NOLINT + // TODO QIR_SHARED_API QirBigInt* __quantum__rt__bigint_power(QirBigInt*, int); // NOLINT // Returns the bitwise-AND of two big integers. - // TODO QIR_SHARED_API QirBigInt* quantum__rt__bigint_bitand(QirBigInt*, QirBigInt*); // NOLINT + // TODO QIR_SHARED_API QirBigInt* __quantum__rt__bigint_bitand(QirBigInt*, QirBigInt*); // NOLINT // Returns the bitwise-OR of two big integers. - // TODO QIR_SHARED_API QirBigInt* quantum__rt__bigint_bitor(QirBigInt*, QirBigInt*); // NOLINT + // TODO QIR_SHARED_API QirBigInt* __quantum__rt__bigint_bitor(QirBigInt*, QirBigInt*); // NOLINT // Returns the bitwise-XOR of two big integers. - // TODO QIR_SHARED_API QirBigInt* quantum__rt__bigint_bitxor(QirBigInt*, QirBigInt*); // NOLINT + // TODO QIR_SHARED_API QirBigInt* __quantum__rt__bigint_bitxor(QirBigInt*, QirBigInt*); // NOLINT // Returns the bitwise complement of the big integer. - // TODO QIR_SHARED_API QirBigInt* quantum__rt__bigint_bitnot(QirBigInt*); // NOLINT + // TODO QIR_SHARED_API QirBigInt* __quantum__rt__bigint_bitnot(QirBigInt*); // NOLINT // Returns the big integer arithmetically shifted left by the integer amount of bits. - // TODO QIR_SHARED_API QirBigInt* quantum__rt__bigint_shiftleft(QirBigInt*, int64_t); // NOLINT + // TODO QIR_SHARED_API QirBigInt* __quantum__rt__bigint_shiftleft(QirBigInt*, int64_t); // NOLINT // Returns the big integer arithmetically shifted right by the integer amount of bits. - // TODO QIR_SHARED_API QirBigInt* quantum__rt__bigint_shiftright(QirBigInt*, int64_t); // NOLINT + // TODO QIR_SHARED_API QirBigInt* __quantum__rt__bigint_shiftright(QirBigInt*, int64_t); // NOLINT // Returns true if the two big integers are equal, false otherwise. - // TODO QIR_SHARED_API bool quantum__rt__bigint_equal(QirBigInt*, QirBigInt*); // NOLINT + // TODO QIR_SHARED_API bool __quantum__rt__bigint_equal(QirBigInt*, QirBigInt*); // NOLINT // Returns true if the first big integer is greater than the second, false otherwise. - // TODO QIR_SHARED_API bool quantum__rt__bigint_greater(QirBigInt*, QirBigInt*); // NOLINT + // TODO QIR_SHARED_API bool __quantum__rt__bigint_greater(QirBigInt*, QirBigInt*); // NOLINT // 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 + // TODO QIR_SHARED_API bool __quantum__rt__bigint_greater_eq(QirBigInt*, QirBigInt*); // NOLINT } -// TODO: Consider separating the `extern "C"` exports and C++ exports. +// TODO(rokuzmin): Consider separating the `extern "C"` exports and C++ exports. namespace Microsoft // Replace with `namespace Microsoft::Quantum` after migration to C++17. { namespace Quantum diff --git a/src/Qir/Runtime/public/QirRuntimeApi_I.hpp b/src/Qir/Runtime/public/QirRuntimeApi_I.hpp index b4e250cdc0e..c5970fcf733 100644 --- a/src/Qir/Runtime/public/QirRuntimeApi_I.hpp +++ b/src/Qir/Runtime/public/QirRuntimeApi_I.hpp @@ -39,5 +39,21 @@ namespace Quantum IRuntimeDriver(const IRuntimeDriver&) = delete; }; + struct QIR_SHARED_API IRestrictedAreaManagement + { + virtual ~IRestrictedAreaManagement() + { + } + IRestrictedAreaManagement() = default; + + virtual void StartArea() = 0; + virtual void NextSegment() = 0; + virtual void EndArea() = 0; + + private: + IRestrictedAreaManagement& operator=(const IRestrictedAreaManagement&) = delete; + IRestrictedAreaManagement(const IRestrictedAreaManagement&) = delete; + }; + } // namespace Quantum } // namespace Microsoft diff --git a/src/Qir/Runtime/public/QirTypes.hpp b/src/Qir/Runtime/public/QirTypes.hpp index cbdf780ec40..3de19d2b2e0 100644 --- a/src/Qir/Runtime/public/QirTypes.hpp +++ b/src/Qir/Runtime/public/QirTypes.hpp @@ -43,13 +43,13 @@ struct QIR_SHARED_API QirArray int AddRef(); int Release(); - QirArray(TItemCount cQubits); + explicit QirArray(TItemCount cQubits); QirArray(TItemCount cItems, TItemSize itemSizeInBytes, TDimCount dimCount = 1, TDimContainer&& dimSizes = {}); QirArray(const QirArray& other); ~QirArray(); - char* GetItemPointer(TItemCount index) const; + [[nodiscard]] char* GetItemPointer(TItemCount index) const; void Append(const QirArray* other); }; @@ -61,8 +61,8 @@ struct QIR_SHARED_API QirString long refCount = 1; std::string str; - QirString(std::string&& str); - QirString(const char* cstr); + explicit QirString(std::string&& str); + explicit QirString(const char* cstr); }; /*====================================================================================================================== @@ -72,10 +72,10 @@ struct QIR_SHARED_API QirString a header that contains the relevant data. The header immediately precedes the tuple's buffer in memory when the tuple is created. ======================================================================================================================*/ -// TODO: Move these types to inside of `QirTupleHeader`. +// TODO (rokuzmin): Move these types to inside of `QirTupleHeader`. using PTuplePointedType = uint8_t; -using PTuple = PTuplePointedType*; // TODO: consider replacing `uint8_t*` with `void*` in order to block the accidental - // {dereferencing and pointer arithmtic}. +using PTuple = PTuplePointedType*; // TODO(rokuzmin): consider replacing `uint8_t*` with `void*` in order to block + // the accidental {dereferencing and pointer arithmetic}. // Much pointer arithmetic in tests. GetHeader() uses the pointer arithmetic. struct QIR_SHARED_API QirTupleHeader { @@ -90,7 +90,7 @@ struct QIR_SHARED_API QirTupleHeader PTuple AsTuple() { - return data; + return (PTuple)data; } int AddRef(); @@ -139,12 +139,12 @@ static_assert(sizeof(TupleWithControls) == 2 * sizeof(void*), /*====================================================================================================================== QirCallable ======================================================================================================================*/ -typedef void (*t_CallableEntry)(PTuple, PTuple, PTuple); // TODO: Move to `QirCallable::t_CallableEntry`. -typedef void (*t_CaptureCallback)(PTuple, int32_t); // TODO: Move to `QirCallable::t_CaptureCallback`. +typedef void (*t_CallableEntry)(PTuple, PTuple, PTuple); // TODO(rokuzmin): Move to `QirCallable::t_CallableEntry`. +typedef void (*t_CaptureCallback)(PTuple, int32_t); // TODO(rokuzmin): Move to `QirCallable::t_CaptureCallback`. struct QIR_SHARED_API QirCallable { static int constexpr Adjoint = 1; - static int constexpr Controlled = 1 << 1; + static int constexpr Controlled = 1u << 1; private: static int constexpr TableSize = 4; @@ -192,11 +192,12 @@ struct QIR_SHARED_API QirCallable void InvokeCaptureCallback(int32_t index, int32_t parameter); }; -struct QIR_SHARED_API QirRange +extern "C" { - int64_t start = 0; - int64_t step = 0; - int64_t end = 0; - - QirRange(int64_t start, int64_t step, int64_t end); -}; + struct QirRange + { + int64_t start; + int64_t step; + int64_t end; + }; +} diff --git a/src/Qir/Runtime/public/QubitManager.hpp b/src/Qir/Runtime/public/QubitManager.hpp index 2beaec7e2cf..d1cb70b173f 100644 --- a/src/Qir/Runtime/public/QubitManager.hpp +++ b/src/Qir/Runtime/public/QubitManager.hpp @@ -208,7 +208,7 @@ namespace Quantum int32_t prevAreaWithFreeQubits = 0; RestrictedReuseArea() = default; - RestrictedReuseArea(QubitListInSharedArray freeQubits); + explicit RestrictedReuseArea(QubitListInSharedArray freeQubits); }; // This is NOT a pure stack! We modify it only by push/pop, but we also iterate over elements. @@ -219,15 +219,16 @@ namespace Quantum CRestrictedReuseAreaStack() = default; CRestrictedReuseAreaStack(const CRestrictedReuseAreaStack&) = delete; CRestrictedReuseAreaStack& operator=(const CRestrictedReuseAreaStack&) = delete; - ~CRestrictedReuseAreaStack() = default; + CRestrictedReuseAreaStack(CRestrictedReuseAreaStack&&) = delete; + CRestrictedReuseAreaStack& operator=(CRestrictedReuseAreaStack&&) = delete; + ~CRestrictedReuseAreaStack() = default; void PushToBack(RestrictedReuseArea area); RestrictedReuseArea PopFromBack(); RestrictedReuseArea& PeekBack(); - int32_t Count() const; + [[nodiscard]] int32_t Count() const; }; - private: void EnsureCapacity(QubitIdType requestedCapacity); // Take free qubit id from a free list without extending capacity. @@ -238,11 +239,12 @@ namespace Quantum // Put qubit id back into a free list for the current restricted reuse area. void ReleaseQubitId(QubitIdType id); - bool IsValidId(QubitIdType id) const; - bool IsDisabledId(QubitIdType id) const; - bool IsFreeId(QubitIdType id) const; - bool IsExplicitlyAllocatedId(QubitIdType id) const; + [[nodiscard]] bool IsValidId(QubitIdType id) const; + [[nodiscard]] bool IsDisabledId(QubitIdType id) const; + [[nodiscard]] bool IsFreeId(QubitIdType id) const; + [[nodiscard]] bool IsExplicitlyAllocatedId(QubitIdType id) const; + private: // Configuration Properties: bool mayExtendCapacity = true; diff --git a/src/Qir/Runtime/unittests/QirRuntimeTests.cpp b/src/Qir/Runtime/unittests/QirRuntimeTests.cpp index bead28cbb7a..b911728643c 100644 --- a/src/Qir/Runtime/unittests/QirRuntimeTests.cpp +++ b/src/Qir/Runtime/unittests/QirRuntimeTests.cpp @@ -80,56 +80,56 @@ TEST_CASE("Results: comparison and reference counting", "[qir_support]") 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)); + 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); + __quantum__rt__result_update_reference_count(r2, -1); // share a result a few times - quantum__rt__result_update_reference_count(r1, 2); + __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 + __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); + __quantum__rt__result_update_reference_count(r3, -1); REQUIRE(!qapi->HaveResultsInFlight()); // no leaks } TEST_CASE("Arrays: one dimensional", "[qir_support]") { - QirArray* a = quantum__rt__array_create_1d(sizeof(char), 5); + 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); + 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_1d(a) == 5); - QirArray* b = new QirArray(1, sizeof(char)); - *quantum__rt__array_get_element_ptr_1d(b, 0) = '!'; + 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) == '!'); + QirArray* ab = __quantum__rt__array_concatenate(a, b); + REQUIRE(__quantum__rt__array_get_size_1d(ab) == 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); + __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]") { const size_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); + 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 (size_t i = 0; i < count; i++) @@ -142,85 +142,85 @@ TEST_CASE("Arrays: multiple dimensions", "[qir_support]") // ... [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); + 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); + 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); + __quantum__rt__array_update_reference_count(a, -1); + __quantum__rt__array_update_reference_count(b, -1); } TEST_CASE("Arrays: copy elision", "[qir_support]") { - QirArray* copy = quantum__rt__array_copy(nullptr, true /*force*/); + QirArray* copy = __quantum__rt__array_copy(nullptr, true /*force*/); CHECK(copy == nullptr); - QirArray* a = quantum__rt__array_create_1d(sizeof(char), 5); + 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*/); + 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(copy, -1); // single alias for the array, but copy enforced - copy = quantum__rt__array_copy(a, true /*force*/); + copy = __quantum__rt__array_copy(a, true /*force*/); CHECK(a != copy); - quantum__rt__array_update_reference_count(copy, -1); + __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*/); + __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(copy, -1); - quantum__rt__array_update_reference_count(a, -1); + __quantum__rt__array_update_reference_count(a, -1); } TEST_CASE("Arrays: empty", "[qir_support]") { - 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); + 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); + __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); + QirArray* a = __quantum__rt__array_create_1d(sizeof(char), 0); + REQUIRE(__quantum__rt__array_get_dim(a) == 1); + REQUIRE(__quantum__rt__array_get_size_1d(a) == 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); + QirArray* a1 = __quantum__rt__array_copy(a, true /*force*/); + REQUIRE(__quantum__rt__array_get_dim(a1) == 1); + REQUIRE(__quantum__rt__array_get_size_1d(a1) == 0); REQUIRE(a1->buffer == nullptr); - quantum__rt__array_update_reference_count(a1, -1); + __quantum__rt__array_update_reference_count(a1, -1); - QirArray* c = quantum__rt__array_create_1d(sizeof(char), 5); + 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); - quantum__rt__array_update_reference_count(c, -1); + QirArray* ac = __quantum__rt__array_concatenate(a, c); + REQUIRE(__quantum__rt__array_get_size_1d(ac) == 5); + QirArray* ca = __quantum__rt__array_concatenate(c, a); + REQUIRE(__quantum__rt__array_get_size_1d(ca) == 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); + __quantum__rt__array_update_reference_count(c, -1); } TEST_CASE("Arrays: check the slice range", "[qir_support]") { const int64_t dim0 = 5; const int64_t dim1 = 6; - QirArray* a = quantum__rt__array_create(sizeof(int), 2, dim0, dim1); + QirArray* a = __quantum__rt__array_create(sizeof(int), 2, dim0, dim1); QirArray* slice = nullptr; // invalid range @@ -245,73 +245,73 @@ TEST_CASE("Arrays: check the slice range", "[qir_support]") // 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); + 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); + 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); + __quantum__rt__array_update_reference_count(a, -1); } TEST_CASE("Arrays: slice of 1D array", "[qir_support]") { const int64_t dim = 5; - QirArray* a = quantum__rt__array_create_1d(sizeof(char), dim); + 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); + 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); + 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); + 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); + __quantum__rt__array_update_reference_count(a, -1); } TEST_CASE("Arrays: reversed slice of 1D array", "[qir_support]") { const int64_t dim = 5; - QirArray* a = quantum__rt__array_create_1d(sizeof(char), dim); + 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}); // Range{1, -dim, 0} == Range{1, -5, 0} == { 1 }. // slice == char[1] == { '1' }. - 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); // slice == dangling pointer. + 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); // slice == dangling pointer. // reversed slices are alwayes disconnected slice = quantum__rt__array_slice(a, 0, {dim - 1, -2, 0}); // Range{dim - 1, -2, 0} == Range{4, -2, 0} == {4, 2, 0}. // slice == char[3] == {'4', '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); + 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); + __quantum__rt__array_update_reference_count(a, -1); } TEST_CASE("Arrays: slice of 3D array", "[qir_support]") @@ -321,7 +321,7 @@ TEST_CASE("Arrays: slice of 3D array", "[qir_support]") const int64_t dim1 = 3; const int64_t dim2 = 4; - QirArray* a = quantum__rt__array_create(sizeof(int), dims, dim0, dim1, dim2); + QirArray* a = __quantum__rt__array_create(sizeof(int), dims, dim0, dim1, dim2); QirArray* slice = nullptr; const size_t count = (size_t)(dim0 * dim1 * dim2); // 60 @@ -337,39 +337,39 @@ TEST_CASE("Arrays: slice of 3D array", "[qir_support]") // ... [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))) == + 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); + 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); + 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); + 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 @@ -379,36 +379,36 @@ TEST_CASE("Arrays: slice of 3D array", "[qir_support]") // ... [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); + 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); + 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); + 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 @@ -418,17 +418,17 @@ TEST_CASE("Arrays: slice of 3D array", "[qir_support]") // ... -- [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); + 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]") @@ -438,7 +438,7 @@ TEST_CASE("Arrays: reversed slice of 3D array", "[qir_support]") const int64_t dim1 = 3; const int64_t dim2 = 4; - QirArray* a = quantum__rt__array_create(sizeof(int), dims, dim0, dim1, dim2); + QirArray* a = __quantum__rt__array_create(sizeof(int), dims, dim0, dim1, dim2); QirArray* slice = nullptr; const size_t count = (size_t)(dim0 * dim1 * dim2); // 60 @@ -454,19 +454,19 @@ TEST_CASE("Arrays: reversed slice of 3D array", "[qir_support]") // ... [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))) == + 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); + 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 @@ -474,13 +474,13 @@ TEST_CASE("Arrays: reversed slice of 3D array", "[qir_support]") // 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); + 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 @@ -490,16 +490,16 @@ TEST_CASE("Arrays: reversed slice of 3D array", "[qir_support]") // ... -- [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); - quantum__rt__array_update_reference_count(a, -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) == 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); + __quantum__rt__array_update_reference_count(a, -1); } TEST_CASE("Arrays: project of 3D array", "[qir_support]") @@ -509,7 +509,7 @@ TEST_CASE("Arrays: project of 3D array", "[qir_support]") const int64_t dim1 = 3; const int64_t dim2 = 4; - QirArray* a = quantum__rt__array_create(sizeof(int), dims, dim0, dim1, dim2); + QirArray* a = __quantum__rt__array_create(sizeof(int), dims, dim0, dim1, dim2); QirArray* project = nullptr; const size_t count = (size_t)(dim0 * dim1 * dim2); // 60 @@ -525,21 +525,21 @@ TEST_CASE("Arrays: project of 3D array", "[qir_support]") // ... [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))) == + 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 = __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 @@ -548,56 +548,56 @@ TEST_CASE("Arrays: project of 3D array", "[qir_support]") // ... -- [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); + 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]") { - QirString* a = quantum__rt__string_create("abc"); - QirString* b = quantum__rt__string_create("abc"); - QirString* c = quantum__rt__string_create("xyz"); + 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); + __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); + __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]") { - QirString* a = quantum__rt__string_create("abc"); - QirString* b = quantum__rt__string_create("xyz"); - QirString* abExpected = quantum__rt__string_create("abcxyz"); + 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); + QirString* ab = __quantum__rt__string_concatenate(a, b); REQUIRE(ab == abExpected); - QirString* aa = quantum__rt__string_concatenate(a, a); + 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); + __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()); } @@ -606,52 +606,52 @@ TEST_CASE("Strings: conversions from built-in types", "[qir_support]") { std::vector strings; - strings.push_back(quantum__rt__int_to_string(0)); + 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)); + 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)); + 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)); + 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)); + 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)); + 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)); + 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)); + 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)); + 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)); + 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)); + 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)); + 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)); + 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)); + 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); + __quantum__rt__string_update_reference_count(qstr, -1); } REQUIRE(AllocatedStrings().empty()); @@ -665,8 +665,8 @@ TEST_CASE("Strings: conversions from custom qir types", "[qir_support]") 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); + __quantum__rt__string_update_reference_count(qstr1, -1); + __quantum__rt__string_update_reference_count(qstr2, -1); REQUIRE(AllocatedStrings().empty()); } @@ -732,30 +732,30 @@ TEST_CASE("Qubits: allocate, release, dump", "[qir_support]") QirExecutionContext::Scoped qirctx(qapi.get()); QirString* qstr = nullptr; - Qubit q = quantum__rt__qubit_allocate(); - qstr = quantum__rt__qubit_to_string(q); + 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); + __quantum__rt__string_update_reference_count(qstr, -1); + __quantum__rt__qubit_release(q); REQUIRE(!qapi->HaveQubitsInFlight()); - QirArray* qs = quantum__rt__qubit_allocate_array(3); + 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); + 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); + __quantum__rt__string_update_reference_count(qstr, -1); - QirArray* copy = quantum__rt__array_copy(qs, true /*force*/); + QirArray* copy = __quantum__rt__array_copy(qs, true /*force*/); REQUIRE(!copy->ownsQubits); - quantum__rt__qubit_release_array(qs); // The `qs` is a dangling pointer from now on. + __quantum__rt__qubit_release_array(qs); // The `qs` is a dangling pointer from now on. REQUIRE(!qapi->HaveQubitsInFlight()); - quantum__rt__array_update_reference_count(copy, -1); + __quantum__rt__array_update_reference_count(copy, -1); } QirTupleHeader* FlattenControlArrays(QirTupleHeader* nestedTuple, int depth); @@ -783,16 +783,16 @@ TEST_CASE("Unpacking input tuples of nested callables (case2)", "[qir_support]") std::unique_ptr qapi = std::make_unique(); QirExecutionContext::Scoped 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); + 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(/* QirArray* */ void*) + sizeof(/*Qubit*/ void*)); + PTuple inner = __quantum__rt__tuple_create(sizeof(/* QirArray* */ void*) + sizeof(/*Qubit*/ void*)); TupleWithControls* innerWithControls = TupleWithControls::FromTuple(inner); innerWithControls->controls = controlsInner; *reinterpret_cast(innerWithControls->AsTuple() + sizeof(/* QirArray* */ void*)) = target; - PTuple outer = quantum__rt__tuple_create(sizeof(/* QirArray* */ void*) + sizeof(/*QirTupleHeader*/ void*)); + PTuple outer = __quantum__rt__tuple_create(sizeof(/* QirArray* */ void*) + sizeof(/*QirTupleHeader*/ void*)); TupleWithControls* outerWithControls = TupleWithControls::FromTuple(outer); outerWithControls->controls = controlsOuter; outerWithControls->innerTuple = innerWithControls; @@ -804,14 +804,14 @@ TEST_CASE("Unpacking input tuples of nested callables (case2)", "[qir_support]") 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); + __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); // The `controlsOuter` is a dangling pointer from now on. - quantum__rt__qubit_release_array(controlsInner); // The `controlsInner` is a dangling pointer from now on. - quantum__rt__qubit_release(target); + __quantum__rt__qubit_release_array(controlsOuter); // The `controlsOuter` is a dangling pointer from now on. + __quantum__rt__qubit_release_array(controlsInner); // The `controlsInner` is a dangling pointer from now on. + __quantum__rt__qubit_release(target); } TEST_CASE("Unpacking input tuples of nested callables (case1)", "[qir_support]") @@ -819,20 +819,20 @@ TEST_CASE("Unpacking input tuples of nested callables (case1)", "[qir_support]") std::unique_ptr qapi = std::make_unique(); QirExecutionContext::Scoped 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); + 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)); + 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(/* QirArray* */ void*) + sizeof(/*Tuple*/ void*)); + PTuple inner = __quantum__rt__tuple_create(sizeof(/* QirArray* */ void*) + sizeof(/*Tuple*/ void*)); TupleWithControls* innerWithControls = TupleWithControls::FromTuple(inner); innerWithControls->controls = controlsInner; *reinterpret_cast(innerWithControls->AsTuple() + sizeof(/* QirArray* */ void*)) = args; - PTuple outer = quantum__rt__tuple_create(sizeof(/* QirArray* */ void*) + sizeof(/*QirTupleHeader*/ void*)); + PTuple outer = __quantum__rt__tuple_create(sizeof(/* QirArray* */ void*) + sizeof(/*QirTupleHeader*/ void*)); TupleWithControls* outerWithControls = TupleWithControls::FromTuple(outer); outerWithControls->controls = controlsOuter; outerWithControls->innerTuple = innerWithControls; @@ -848,33 +848,33 @@ TEST_CASE("Unpacking input tuples of nested callables (case1)", "[qir_support]") 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); + __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); // The `controlsOuter` is a dangling pointer from now on. - quantum__rt__qubit_release_array(controlsInner); // The `controlsInner` is a dangling pointer from now on. - quantum__rt__qubit_release(target); + __quantum__rt__qubit_release_array(controlsOuter); // The `controlsOuter` is a dangling pointer from now on. + __quantum__rt__qubit_release_array(controlsInner); // The `controlsInner` is a dangling pointer from now on. + __quantum__rt__qubit_release(target); } TEST_CASE("Allocation tracking for arrays", "[qir_support]") { QirExecutionContext::Init(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* 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* 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); + QirArray* maybeLeaked = __quantum__rt__array_create_1d(1, 1); CHECK_THROWS(QirExecutionContext::Deinit()); - quantum__rt__array_update_reference_count(maybeLeaked, -1); + __quantum__rt__array_update_reference_count(maybeLeaked, -1); CHECK_NOTHROW(QirExecutionContext::Deinit()); } @@ -882,18 +882,18 @@ TEST_CASE("Allocation tracking for tuples", "[qir_support]") { QirExecutionContext::Init(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 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 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); + PTuple maybeLeaked = __quantum__rt__tuple_create(1); CHECK_THROWS(QirExecutionContext::Deinit()); - quantum__rt__tuple_update_reference_count(maybeLeaked, -1); + __quantum__rt__tuple_update_reference_count(maybeLeaked, -1); CHECK_NOTHROW(QirExecutionContext::Deinit()); } @@ -907,20 +907,20 @@ TEST_CASE("Allocation tracking for callables", "[qir_support]") QirExecutionContext::Init(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)); + __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)); + __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*/); + __quantum__rt__callable_create(entries, nullptr /*capture callbacks*/, nullptr /*capture tuple*/); CHECK_THROWS(QirExecutionContext::Deinit()); - quantum__rt__callable_update_reference_count(maybeLeaked, -1); + __quantum__rt__callable_update_reference_count(maybeLeaked, -1); CHECK_NOTHROW(QirExecutionContext::Deinit()); } @@ -930,44 +930,44 @@ TEST_CASE("Callables: copy elision", "[qir_support]") t_CallableEntry entries[4] = {NoopCallableEntry, nullptr, nullptr, nullptr}; QirCallable* original = - quantum__rt__callable_create(entries, nullptr /*capture callbacks*/, nullptr /*capture tuple*/); + __quantum__rt__callable_create(entries, nullptr /*capture callbacks*/, nullptr /*capture tuple*/); - QirCallable* self = quantum__rt__callable_copy(original, false); + QirCallable* self = __quantum__rt__callable_copy(original, false); CHECK(self == original); - QirCallable* other1 = quantum__rt__callable_copy(original, true); + 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); + __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_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); + __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 original = __quantum__rt__tuple_create(1 /*size in bytes*/); - PTuple self = quantum__rt__tuple_copy(original, false); + PTuple self = __quantum__rt__tuple_copy(original, false); CHECK(self == original); - PTuple other1 = quantum__rt__tuple_copy(original, true); + 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); + __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_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); + __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. @@ -1027,16 +1027,17 @@ TEST_CASE("Adjoints of R should use inverse of the angle", "[qir_support]") const double angle = 0.42; - Qubit target = quantum__rt__qubit_allocate(); - QirArray* ctrls = quantum__rt__qubit_allocate_array(2); + 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__qis__r__body(PauliId_Y, angle, target); + __quantum__qis__r__adj(PauliId_Y, angle, target); + QirRTuple args = {PauliId_X, angle, target}; + __quantum__qis__r__ctl(ctrls, &args); + __quantum__qis__r__ctladj(ctrls, &args); - quantum__rt__qubit_release_array(ctrls); // The `ctrls` is a dangling pointer from now on. - quantum__rt__qubit_release(target); + __quantum__rt__qubit_release_array(ctrls); // The `ctrls` is a dangling pointer from now on. + __quantum__rt__qubit_release(target); REQUIRE(qapi->rotationAngle == Approx(0).epsilon(0.0001)); } @@ -1048,20 +1049,21 @@ TEST_CASE("Adjoints of Exp should use inverse of the angle", "[qir_support]") 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__array_update_reference_count(axes, -1); - quantum__rt__qubit_release_array(ctrls); // The `ctrls` is a dangling pointer from now on. - quantum__rt__qubit_release_array(targets); // The `targets` is a dangling pointer from now on. + 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] = PauliId_Z; + axes->buffer[1] = PauliId_Y; + + __quantum__qis__exp__body(axes, angle, targets); + __quantum__qis__exp__adj(axes, angle, targets); + QirExpTuple args = {axes, angle, targets}; + __quantum__qis__exp__ctl(ctrls, &args); + __quantum__qis__exp__ctladj(ctrls, &args); + + __quantum__rt__array_update_reference_count(axes, -1); + __quantum__rt__qubit_release_array(ctrls); // The `ctrls` is a dangling pointer from now on. + __quantum__rt__qubit_release_array(targets); // The `targets` is a dangling pointer from now on. REQUIRE(qapi->exponentAngle == Approx(0).epsilon(0.0001)); } diff --git a/src/Qir/Samples/StandaloneInputReference/.clang-tidy b/src/Qir/Samples/StandaloneInputReference/.clang-tidy index af1d9665a68..eece2bb3472 100644 --- a/src/Qir/Samples/StandaloneInputReference/.clang-tidy +++ b/src/Qir/Samples/StandaloneInputReference/.clang-tidy @@ -1,5 +1,5 @@ InheritParentConfig: true Checks: - '-bugprone-exception-escape*' + '-bugprone-exception-escape,-cert-err58-cpp' HeaderFilterRegex: '' diff --git a/src/Qir/Tests/.clang-tidy b/src/Qir/Tests/.clang-tidy new file mode 100644 index 00000000000..8b9489eeabb --- /dev/null +++ b/src/Qir/Tests/.clang-tidy @@ -0,0 +1,3 @@ +InheritParentConfig: true +Checks: + '-cert-err58-cpp' diff --git a/src/Qir/Tests/QIR-dynamic/qsharp/qir-test-assert.qs b/src/Qir/Tests/QIR-dynamic/qsharp/qir-test-assert.qs index 81ecafe51a0..e039eb71224 100644 --- a/src/Qir/Tests/QIR-dynamic/qsharp/qir-test-assert.qs +++ b/src/Qir/Tests/QIR-dynamic/qsharp/qir-test-assert.qs @@ -172,7 +172,7 @@ namespace Microsoft.Quantum.Testing.QIR { // Multiple qubits: // Quantum Katas, Joint Measurement Workbook, - // https://mybinder.org/v2/gh/microsoft/QuantumKatas/HEAD?filepath=JointMeasurements%2FWorkbook_JointMeasurements.ipynb + // https://mybinder.org/v2/gh/microsoft/QuantumKatas/main?urlpath=/notebooks/JointMeasurements%2FWorkbook_JointMeasurements.ipynb // Task 1. Single-qubit measurement // Task 2. Parity measurement diff --git a/src/Qir/Tests/QIR-static/CMakeLists.txt b/src/Qir/Tests/QIR-static/CMakeLists.txt index c6a57062153..323d8222a7e 100644 --- a/src/Qir/Tests/QIR-static/CMakeLists.txt +++ b/src/Qir/Tests/QIR-static/CMakeLists.txt @@ -1,6 +1,6 @@ set(TEST_FILES qir-test-noqsharp.ll - qsharp/obj/qsharp/qir-gen.bc + qsharp/qir/qir-gen.ll ) #============================================================================== diff --git a/src/Qir/Tests/QIR-static/qir-test-math.cpp b/src/Qir/Tests/QIR-static/qir-test-math.cpp index 038eb44697f..91e0e09857c 100644 --- a/src/Qir/Tests/QIR-static/qir-test-math.cpp +++ b/src/Qir/Tests/QIR-static/qir-test-math.cpp @@ -11,6 +11,7 @@ extern "C" uint64_t Microsoft__Quantum__Testing__QIR__Math__SqrtTest__Interop(); // NOLINT extern "C" uint64_t Microsoft__Quantum__Testing__QIR__Math__LogTest__Interop(); // NOLINT +extern "C" uint64_t Microsoft__Quantum__Testing__QIR__Math__InfTest__Interop(); // NOLINT extern "C" uint64_t Microsoft__Quantum__Testing__QIR__Math__ArcTan2Test__Interop(); // NOLINT extern "C" uint64_t Microsoft__Quantum__Testing__QIR__Math__SinTest__Interop(); // NOLINT extern "C" uint64_t Microsoft__Quantum__Testing__QIR__Math__CosTest__Interop(); // NOLINT @@ -37,6 +38,11 @@ TEST_CASE("QIR: Math.Log", "[qir.math][qir.Math.Log]") REQUIRE(0 == Microsoft__Quantum__Testing__QIR__Math__LogTest__Interop()); } +TEST_CASE("QIR: Math.Inf", "[qir.math][qir.Math.Inf]") +{ + REQUIRE(0 == Microsoft__Quantum__Testing__QIR__Math__InfTest__Interop()); +} + TEST_CASE("QIR: Math.ArcTan2", "[qir.math][qir.Math.ArcTan2]") { REQUIRE(0 == Microsoft__Quantum__Testing__QIR__Math__ArcTan2Test__Interop()); diff --git a/src/Qir/Tests/QIR-static/qsharp/qir-test-math.qs b/src/Qir/Tests/QIR-static/qsharp/qir-test-math.qs index 2b915bcad0f..000260ef140 100644 --- a/src/Qir/Tests/QIR-static/qsharp/qir-test-math.qs +++ b/src/Qir/Tests/QIR-static/qsharp/qir-test-math.qs @@ -34,6 +34,19 @@ namespace Microsoft.Quantum.Testing.QIR.Math { return 0; } + @EntryPoint() + function InfTest() : Int { + if IsInf(0.0) { return 1; } + if not IsInf(INFINITY()) { return 2; } + if IsInf(-INFINITY()) { return 3; } + + if IsNegativeInfinity(0.0) { return 4; } + if not IsNegativeInfinity(-INFINITY()) { return 5; } + if IsNegativeInfinity(INFINITY()) { return 6; } + + return 0; + } + @EntryPoint() function ArcTan2Test() : Int { diff --git a/src/Qir/Tests/Tools/QirDriverGeneratorTests.cs b/src/Qir/Tests/Tools/QirDriverGeneratorTests.cs index b8282822ee3..e3e1cd3eaad 100644 --- a/src/Qir/Tests/Tools/QirDriverGeneratorTests.cs +++ b/src/Qir/Tests/Tools/QirDriverGeneratorTests.cs @@ -23,6 +23,10 @@ public class QirDriverGeneratorTests "UseNoArgs", new EntryPointOperation{Name = "UseNoArgs"} }, + { + "UseNoArgsDebug", + new EntryPointOperation{Name = "UseNoArgsDebug"} + }, { "UseBoolArg", new EntryPointOperation @@ -43,7 +47,7 @@ public class QirDriverGeneratorTests "UseDoubleArg", new EntryPointOperation { - Name = "UseDoublArg", + Name = "UseDoubleArg", Parameters = new List{new Parameter{ Name = "DoubleArg", Type = DataType.DoubleType}} } }, @@ -146,25 +150,26 @@ public class QirDriverGeneratorTests str.Replace("\n", string.Empty).Replace("\r", string.Empty); [Theory] - [InlineData("UseNoArgs")] - [InlineData("UseBoolArg")] - [InlineData("UseBoolArrayArg")] - [InlineData("UseDoubleArg")] - [InlineData("UseDoubleArrayArg")] - [InlineData("UseIntegerArg")] - [InlineData("UseIntegerArrayArg")] - [InlineData("UsePauliArg")] - [InlineData("UsePauliArrayArg")] - [InlineData("UseRangeArg")] - [InlineData("UseRangeArrayArg")] - [InlineData("UseResultArg")] - [InlineData("UseResultArrayArg")] - [InlineData("UseStringArg")] - [InlineData("UseMiscArgs")] - public void GenerateFullStateSimulatorDriver(string testCase) + [InlineData("UseNoArgs", false)] + [InlineData("UseNoArgsDebug", true)] + [InlineData("UseBoolArg", false)] + [InlineData("UseBoolArrayArg", false)] + [InlineData("UseDoubleArg", false)] + [InlineData("UseDoubleArrayArg", false)] + [InlineData("UseIntegerArg", false)] + [InlineData("UseIntegerArrayArg", false)] + [InlineData("UsePauliArg", false)] + [InlineData("UsePauliArrayArg", false)] + [InlineData("UseRangeArg", false)] + [InlineData("UseRangeArrayArg", false)] + [InlineData("UseResultArg", false)] + [InlineData("UseResultArrayArg", false)] + [InlineData("UseStringArg", false)] + [InlineData("UseMiscArgs", false)] + public void GenerateFullStateSimulatorDriver(string testCase, bool debug) { var entryPointOperation = TestCases[testCase]; - var driverGenerator = new QirFullStateDriverGenerator(); + var driverGenerator = new QirFullStateDriverGenerator(debug); var driverFileName = $"{testCase}.cpp"; var verificationCppSourceCode = RemoveLineEndings(File.ReadAllText(Path.Combine(TestCasesDirectory, driverFileName))); Directory.CreateDirectory(TestArtifactsDirectory); @@ -174,7 +179,6 @@ public void GenerateFullStateSimulatorDriver(string testCase) var generatedCppSourceCode = RemoveLineEndings(generatedStreamReader.ReadToEnd()); Assert.Equal(verificationCppSourceCode, generatedCppSourceCode); generatedStream.Close(); - } } } diff --git a/src/Qir/Tests/Tools/TestCases/FullStateDriverGenerator/UseDoubleArg.cpp b/src/Qir/Tests/Tools/TestCases/FullStateDriverGenerator/UseDoubleArg.cpp index d21ac1896b9..4f906afb33b 100644 --- a/src/Qir/Tests/Tools/TestCases/FullStateDriverGenerator/UseDoubleArg.cpp +++ b/src/Qir/Tests/Tools/TestCases/FullStateDriverGenerator/UseDoubleArg.cpp @@ -21,7 +21,7 @@ using namespace Microsoft::Quantum; using namespace std; -extern "C" void UseDoublArg( +extern "C" void UseDoubleArg( double_t DoubleArg ); // QIR interop function. @@ -63,7 +63,7 @@ int main(int argc, char* argv[]) } // Execute the entry point operation. - UseDoublArg( + UseDoubleArg( DoubleArgInterop ); diff --git a/src/Qir/Tests/Tools/TestCases/FullStateDriverGenerator/UseNoArgsDebug.cpp b/src/Qir/Tests/Tools/TestCases/FullStateDriverGenerator/UseNoArgsDebug.cpp new file mode 100644 index 00000000000..847066fd763 --- /dev/null +++ b/src/Qir/Tests/Tools/TestCases/FullStateDriverGenerator/UseNoArgsDebug.cpp @@ -0,0 +1,67 @@ +//---------------------------------------------------------------------------------------------------------------------- +// +// This code was generated by the Microsoft.Quantum.Qir.Runtime.Tools package. +// The purpose of this source code file is to provide an entry-point for executing a QIR program. +// It handles parsing of command line arguments, and it invokes an entry-point function exposed by the QIR program. +//---------------------------------------------------------------------------------------------------------------------- + +#include +#include +#include +#include +#include + +#include "CLI11.hpp" + +#include "QirRuntime.hpp" +#include "QirContext.hpp" + +#include "SimFactory.hpp" + +using namespace Microsoft::Quantum; +using namespace std; + +extern "C" void UseNoArgsDebug( +); // QIR interop function. + +int main(int argc, char* argv[]) +{ + CLI::App app("QIR Standalone Entry Point"); + + // Initialize runtime. + unique_ptr sim = CreateFullstateSimulator(); + QirContextScope qirctx(sim.get(), true /*trackAllocatedObjects*/); + + // Add the --simulation-output option. + string simulationOutputFile; + CLI::Option* simulationOutputFileOpt = app.add_option( + "--simulation-output", + simulationOutputFile, + "File where the output produced during the simulation is written"); + + // After all the options have been added, parse arguments from the command line. + CLI11_PARSE(app, argc, argv); + + // Redirect the simulator output from std::cout if the --simulation-output option is present. + ostream* simulatorOutputStream = &cout; + ofstream simulationOutputFileStream; + if (!simulationOutputFileOpt->empty()) + { + simulationOutputFileStream.open(simulationOutputFile); + SetOutputStream(simulationOutputFileStream); + simulatorOutputStream = &simulationOutputFileStream; + } + + // Execute the entry point operation. + UseNoArgsDebug( + ); + + // Flush the output of the simulation. + simulatorOutputStream->flush(); + if (simulationOutputFileStream.is_open()) + { + simulationOutputFileStream.close(); + } + + return 0; +} diff --git a/src/Qir/Tests/Tools/Tests.Microsoft.Quantum.Qir.Runtime.Tools.csproj b/src/Qir/Tests/Tools/Tests.Microsoft.Quantum.Qir.Runtime.Tools.csproj index 8474a7ece46..23f2d9c6982 100644 --- a/src/Qir/Tests/Tools/Tests.Microsoft.Quantum.Qir.Runtime.Tools.csproj +++ b/src/Qir/Tests/Tools/Tests.Microsoft.Quantum.Qir.Runtime.Tools.csproj @@ -64,6 +64,9 @@ Always + + Always + diff --git a/src/Qir/Tools/Driver/QirCppFullStateSimulatorInitializer.cs b/src/Qir/Tools/Driver/QirCppFullStateSimulatorInitializer.cs index 1385f4d6da4..eaa6e5d4cf5 100644 --- a/src/Qir/Tools/Driver/QirCppFullStateSimulatorInitializer.cs +++ b/src/Qir/Tools/Driver/QirCppFullStateSimulatorInitializer.cs @@ -22,8 +22,9 @@ public partial class QirCppFullStateSimulatorInitializer : QirCppFullStateSimula /// public virtual string TransformText() { - this.Write("unique_ptr sim = CreateFullstateSimulator();\r\nQirContextScope qir" + - "ctx(sim.get(), false /*trackAllocatedObjects*/);"); + this.Write("unique_ptr sim = CreateFullstateSimulator();\r\nQirContextScope qirctx(sim.get(), "); + this.Write(this.ToStringHelper.ToStringWithCulture(this.debug ? "true" : "false")); + this.Write(" /*trackAllocatedObjects*/);"); return this.GenerationEnvironment.ToString(); } } diff --git a/src/Qir/Tools/Driver/QirCppFullStateSimulatorInitializer.tt b/src/Qir/Tools/Driver/QirCppFullStateSimulatorInitializer.tt index 275994cf4af..9b9eb0f4457 100644 --- a/src/Qir/Tools/Driver/QirCppFullStateSimulatorInitializer.tt +++ b/src/Qir/Tools/Driver/QirCppFullStateSimulatorInitializer.tt @@ -1,3 +1,3 @@ <#@ template language="C#" linePragmas="false" #> unique_ptr sim = CreateFullstateSimulator(); -QirContextScope qirctx(sim.get(), false /*trackAllocatedObjects*/); \ No newline at end of file +QirContextScope qirctx(sim.get(), <#= this.debug ? "true" : "false" #> /*trackAllocatedObjects*/); \ No newline at end of file diff --git a/src/Qir/Tools/Driver/QirCppFullStateSimulatorInitializerEx.cs b/src/Qir/Tools/Driver/QirCppFullStateSimulatorInitializerEx.cs new file mode 100644 index 00000000000..793965e657f --- /dev/null +++ b/src/Qir/Tools/Driver/QirCppFullStateSimulatorInitializerEx.cs @@ -0,0 +1,9 @@ +namespace Microsoft.Quantum.Qir.Runtime.Tools.Driver +{ + public partial class QirCppFullStateSimulatorInitializer + { + private readonly bool debug; + + internal QirCppFullStateSimulatorInitializer(bool debug) => this.debug = debug; + } +} diff --git a/src/Qir/Tools/Driver/QirFullStateDriverGenerator.cs b/src/Qir/Tools/Driver/QirFullStateDriverGenerator.cs index 475fca1b571..aadfa0a4577 100644 --- a/src/Qir/Tools/Driver/QirFullStateDriverGenerator.cs +++ b/src/Qir/Tools/Driver/QirFullStateDriverGenerator.cs @@ -10,10 +10,9 @@ namespace Microsoft.Quantum.Qir.Runtime.Tools.Driver public class QirFullStateDriverGenerator: IQirDriverGenerator { private readonly QirCppDriverGenerator DriverGenerator; - public QirFullStateDriverGenerator() - { - DriverGenerator = new QirCppDriverGenerator(new QirFullStateSimulatorInitializer()); - } + + public QirFullStateDriverGenerator(bool debug) => + DriverGenerator = new QirCppDriverGenerator(new QirFullStateSimulatorInitializer(debug)); public async Task GenerateAsync(EntryPointOperation entryPoint, Stream stream) => await DriverGenerator.GenerateAsync(entryPoint, stream); diff --git a/src/Qir/Tools/Driver/QirFullStateSimulatorInitializer.cs b/src/Qir/Tools/Driver/QirFullStateSimulatorInitializer.cs index a85ebb62143..ca5af5d863a 100644 --- a/src/Qir/Tools/Driver/QirFullStateSimulatorInitializer.cs +++ b/src/Qir/Tools/Driver/QirFullStateSimulatorInitializer.cs @@ -7,7 +7,11 @@ namespace Microsoft.Quantum.Qir.Runtime.Tools.Driver { public class QirFullStateSimulatorInitializer : IQirRuntimeInitializer { - public string Generate() => new QirCppFullStateSimulatorInitializer().TransformText(); + private readonly bool debug; + + internal QirFullStateSimulatorInitializer(bool debug) => this.debug = debug; + + public string Generate() => new QirCppFullStateSimulatorInitializer(this.debug).TransformText(); public IEnumerable Headers => new [] { "SimFactory.hpp" diff --git a/src/Qir/Tools/Executable/QirExecutableRunner.cs b/src/Qir/Tools/Executable/QirExecutableRunner.cs index ab375e538bd..1c9038d5c52 100644 --- a/src/Qir/Tools/Executable/QirExecutableRunner.cs +++ b/src/Qir/Tools/Executable/QirExecutableRunner.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +using System; using System.Diagnostics; using System.IO; using System.Threading.Tasks; @@ -37,6 +38,11 @@ public async Task RunExecutableAsync(FileInfo executableFile, Stream stream, str using var streamWriter = new StreamWriter(stream); await streamWriter.WriteAsync(output); logger?.LogInformation($"Executable has finished running. Result code: {process.ExitCode}"); + + if (process.ExitCode != 0) + { + throw new InvalidOperationException($"Executable failed with exit code: {process.ExitCode}"); + } } } } diff --git a/src/Qir/Tools/Executable/QirFullStateExecutable.cs b/src/Qir/Tools/Executable/QirFullStateExecutable.cs index eacb49ca582..b6c4e3709c7 100644 --- a/src/Qir/Tools/Executable/QirFullStateExecutable.cs +++ b/src/Qir/Tools/Executable/QirFullStateExecutable.cs @@ -30,11 +30,8 @@ public class QirFullStateExecutable : QirExecutable public override IList LibraryDirectories { get; } = new List(); - public QirFullStateExecutable(FileInfo executableFile, byte[] qirBitcode, ILogger? logger = null) - : base(executableFile, - qirBitcode, - new QirFullStateDriverGenerator(), - logger) + internal QirFullStateExecutable(FileInfo executableFile, byte[] qirBitcode, bool debug, ILogger? logger = null) + : base(executableFile, qirBitcode, new QirFullStateDriverGenerator(debug), logger) { var thisModulePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); if (string.IsNullOrWhiteSpace(thisModulePath)) diff --git a/src/Qir/Tools/Microsoft.Quantum.Qir.Runtime.Tools.csproj b/src/Qir/Tools/Microsoft.Quantum.Qir.Runtime.Tools.csproj index aad87d2c3a9..a3bb0999528 100644 --- a/src/Qir/Tools/Microsoft.Quantum.Qir.Runtime.Tools.csproj +++ b/src/Qir/Tools/Microsoft.Quantum.Qir.Runtime.Tools.csproj @@ -1,5 +1,7 @@  + + netstandard2.1 x64 diff --git a/src/Qir/Tools/QirTools.cs b/src/Qir/Tools/QirTools.cs index d82960fc3c7..a159d75f072 100644 --- a/src/Qir/Tools/QirTools.cs +++ b/src/Qir/Tools/QirTools.cs @@ -23,11 +23,13 @@ public static class QirTools /// Directory where the libraries to link to are located. /// Directory where the headers needed for compilation are located. /// Directory where the created executables are placed. + /// Enable additional debugging checks at runtime. public static async Task BuildFromQSharpDll( FileInfo qsharpDll, IList libraryDirectories, IList includeDirectories, - DirectoryInfo executablesDirectory) + DirectoryInfo executablesDirectory, + bool debug) { using var qirContentStream = new MemoryStream(); if (!AssemblyLoader.LoadQirBitcode(qsharpDll, qirContentStream)) @@ -42,7 +44,7 @@ public static class QirTools foreach (var entryPointOp in EntryPointLoader.LoadEntryPointOperations(qsharpDll)) { var exeFileInfo = new FileInfo(Path.Combine(executablesDirectory.FullName, $"{entryPointOp.Name}.exe")); - var exe = new QirFullStateExecutable(exeFileInfo, qirContentStream.ToArray()); + var exe = new QirFullStateExecutable(exeFileInfo, qirContentStream.ToArray(), debug); await exe.BuildAsync(entryPointOp, libraryDirectories, includeDirectories); } diff --git a/src/Qir/check-sources-formatted.ps1 b/src/Qir/check-sources-formatted.ps1 index 9eafcad30ef..d99f1441556 100644 --- a/src/Qir/check-sources-formatted.ps1 +++ b/src/Qir/check-sources-formatted.ps1 @@ -12,6 +12,11 @@ param ( if (-not $IsMacOS) { # We do not control the clang-format version on MacOS, and that version (12.0.1) requires formatting contradicting the version on Win and Linux (11.1.0). $tmpFile = "format.log" + $clangFormatCommand = "clang-format" + if(($IsLinux) -or ((Test-Path Env:/AGENT_OS) -and ($Env:AGENT_OS.StartsWith("Lin")))) { + $script:clangFormatCommand = "clang-format-11" + } + $OldErrorActionPreference = $ErrorActionPreference $ErrorActionPreference='Continue' "*.cpp", "*.c", "*.h", "*.hpp" ` @@ -24,7 +29,7 @@ if (-not $IsMacOS) { # We do not control the clang-format version on MacOS, an | Where-Object { $_ -notlike "*/bin/*" } ` | Where-Object {$_ -notlike "*/FullStateDriverGenerator/*"} ` | ForEach-Object { - clang-format -n -style=file $_ + & $clangFormatCommand -n -style=file $_ } 2>$tmpFile $ErrorActionPreference=$OldErrorActionPreference @@ -38,7 +43,7 @@ if (-not $IsMacOS) { # We do not control the clang-format version on MacOS, an Write-Host "##vso[task.logissue type=error;]Formatting check failed. The following files need to be formatted before compiling: " Write-Host "(You may use the Clang-Format extension in VSCode, clang-format in command line, or see https://clang.llvm.org/docs/ClangFormat.html)" $filesRequireFormatting | Format-Table - clang-format --version + & $clangFormatCommand --version throw "Formatting check failed for QIR Runtime sources" } } diff --git a/src/Qir/qir-utils.ps1 b/src/Qir/qir-utils.ps1 index 4f326c6634b..2d507d87e3e 100644 --- a/src/Qir/qir-utils.ps1 +++ b/src/Qir/qir-utils.ps1 @@ -173,7 +173,7 @@ function Build-CMakeProject { } # if ($Env:BUILD_CONFIGURATION -eq "Debug") - if (($IsMacOS) -or ((Test-Path Env:AGENT_OS) -and ($Env:AGENT_OS.StartsWith("Darwin")))) + 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)" } diff --git a/src/Simulation/AutoSubstitution/Microsoft.Quantum.AutoSubstitution.csproj b/src/Simulation/AutoSubstitution/Microsoft.Quantum.AutoSubstitution.csproj index 88af43a8d50..a6f334bb90e 100644 --- a/src/Simulation/AutoSubstitution/Microsoft.Quantum.AutoSubstitution.csproj +++ b/src/Simulation/AutoSubstitution/Microsoft.Quantum.AutoSubstitution.csproj @@ -14,7 +14,7 @@ false false false - false + true false diff --git a/src/Simulation/QSharpFoundation/Diagnostics/Assert.qs b/src/Simulation/QSharpFoundation/Diagnostics/Assert.qs index a8df5b312ce..a53b4da78ca 100644 --- a/src/Simulation/QSharpFoundation/Diagnostics/Assert.qs +++ b/src/Simulation/QSharpFoundation/Diagnostics/Assert.qs @@ -86,6 +86,7 @@ namespace Microsoft.Quantum.Diagnostics { operation AssertMeasurementProbability(bases : Pauli[], qubits : Qubit[], result : Result, prob : Double, msg : String, tolerance : Double) : Unit is Adj + Ctl { body intrinsic; + adjoint self; } } diff --git a/src/Simulation/Simulators/QuantumSimulator/MZ.cs b/src/Simulation/Simulators/QuantumSimulator/MZ.cs new file mode 100644 index 00000000000..2d4cdbc4d94 --- /dev/null +++ b/src/Simulation/Simulators/QuantumSimulator/MZ.cs @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.Quantum.Simulation.Core; +using Microsoft.Quantum.Intrinsic.Interfaces; + +namespace Microsoft.Quantum.Simulation.Simulators +{ + public partial class QuantumSimulator + { + Result IIntrinsicMZ.Body(Qubit target) + { + this.CheckQubit(target); + //setting qubit as measured to allow for release + target.IsMeasured = true; + return M(this.Id, (uint)target.Id).ToResult(); + } + } +} diff --git a/src/Simulation/TargetDefinitions/Decompositions/MResetXExplicit.qs b/src/Simulation/TargetDefinitions/Decompositions/MResetXExplicit.qs index 0254cd0fc6e..18fb40bdb85 100644 --- a/src/Simulation/TargetDefinitions/Decompositions/MResetXExplicit.qs +++ b/src/Simulation/TargetDefinitions/Decompositions/MResetXExplicit.qs @@ -22,7 +22,7 @@ namespace Microsoft.Quantum.Measurement { /// The result of measuring `target` in the Pauli $X$ basis. operation MResetX (target : Qubit) : Result { MapPauli(target, PauliZ, PauliX); - let result = M(target); + let result = MZ(target); Reset(target); return result; } diff --git a/src/Simulation/TargetDefinitions/Decompositions/MResetYExplicit.qs b/src/Simulation/TargetDefinitions/Decompositions/MResetYExplicit.qs index 940b959b726..46af84c317c 100644 --- a/src/Simulation/TargetDefinitions/Decompositions/MResetYExplicit.qs +++ b/src/Simulation/TargetDefinitions/Decompositions/MResetYExplicit.qs @@ -22,7 +22,7 @@ namespace Microsoft.Quantum.Measurement { /// The result of measuring `target` in the Pauli $Y$ basis. operation MResetY (target : Qubit) : Result { MapPauli(target, PauliZ, PauliY); - let result = M(target); + let result = MZ(target); Reset(target); return result; } diff --git a/src/Simulation/TargetDefinitions/Decompositions/MResetZExplicit.qs b/src/Simulation/TargetDefinitions/Decompositions/MResetZExplicit.qs index 00fafd690db..77fcceb66b5 100644 --- a/src/Simulation/TargetDefinitions/Decompositions/MResetZExplicit.qs +++ b/src/Simulation/TargetDefinitions/Decompositions/MResetZExplicit.qs @@ -21,7 +21,7 @@ namespace Microsoft.Quantum.Measurement { /// # Output /// The result of measuring `target` in the Pauli $Z$ basis. operation MResetZ (target : Qubit) : Result { - let result = M(target); + let result = MZ(target); Reset(target); return result; } diff --git a/src/Simulation/TargetDefinitions/Decompositions/MWithPostPrep.qs b/src/Simulation/TargetDefinitions/Decompositions/MWithPostPrep.qs new file mode 100644 index 00000000000..964519db71e --- /dev/null +++ b/src/Simulation/TargetDefinitions/Decompositions/MWithPostPrep.qs @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Intrinsic { + + /// # Summary + /// Performs a measurement of a single qubit in the + /// Pauli $Z$ basis. + /// + /// # Description + /// The output result is given by + /// the distribution + /// \begin{align} + /// \Pr(\texttt{Zero} | \ket{\psi}) = + /// \braket{\psi | 0} \braket{0 | \psi}. + /// \end{align} + /// + /// # Input + /// ## qubit + /// Qubit to be measured. + /// + /// # Output + /// `Zero` if the $+1$ eigenvalue is observed, and `One` if + /// the $-1$ eigenvalue is observed. + /// + /// # Remarks + /// Equivalent to: + /// ```qsharp + /// Measure([PauliZ], [qubit]); + /// ``` + operation M (qubit : Qubit) : Result { + let result = MZ(qubit); + PreparePostM(result, qubit); + return result; + } +} \ No newline at end of file diff --git a/src/Simulation/TargetDefinitions/Interfaces/IIntrinsicMZ.cs b/src/Simulation/TargetDefinitions/Interfaces/IIntrinsicMZ.cs new file mode 100644 index 00000000000..5b6d1919061 --- /dev/null +++ b/src/Simulation/TargetDefinitions/Interfaces/IIntrinsicMZ.cs @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Intrinsic.Interfaces +{ + public interface IIntrinsicMZ : IOperationFactory + { + Result Body(Qubit target); + } +} \ No newline at end of file diff --git a/src/Simulation/TargetDefinitions/Interfaces/IType1Core.cs b/src/Simulation/TargetDefinitions/Interfaces/IType1Core.cs index 6f28f98aa5f..96ef2209d17 100644 --- a/src/Simulation/TargetDefinitions/Interfaces/IType1Core.cs +++ b/src/Simulation/TargetDefinitions/Interfaces/IType1Core.cs @@ -17,7 +17,7 @@ public interface IType1Core : IIntrinsicApplyUncontrolledX, IIntrinsicApplyUncontrolledY, IIntrinsicApplyUncontrolledZ, - IIntrinsicM, + IIntrinsicMZ, IIntrinsicReset { } } \ No newline at end of file diff --git a/src/Simulation/TargetDefinitions/Interfaces/IType3Core.cs b/src/Simulation/TargetDefinitions/Interfaces/IType3Core.cs index 5d4b589620f..4cfa80d051d 100644 --- a/src/Simulation/TargetDefinitions/Interfaces/IType3Core.cs +++ b/src/Simulation/TargetDefinitions/Interfaces/IType3Core.cs @@ -18,7 +18,7 @@ public interface IType3Core : IIntrinsicApplyUncontrolledX, IIntrinsicApplyUncontrolledY, IIntrinsicApplyUncontrolledZ, - IIntrinsicM, + IIntrinsicMZ, IIntrinsicReset { } } \ No newline at end of file diff --git a/src/Simulation/TargetDefinitions/Intrinsic/MZ.qs b/src/Simulation/TargetDefinitions/Intrinsic/MZ.qs new file mode 100644 index 00000000000..c75bfa1e221 --- /dev/null +++ b/src/Simulation/TargetDefinitions/Intrinsic/MZ.qs @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Intrinsic { + open Microsoft.Quantum.Targeting; + + /// # Summary + /// Performs a measurement of a single qubit in the + /// Pauli $Z$ basis. + /// + /// # Description + /// The output result is given by + /// the distribution + /// \begin{align} + /// \Pr(\texttt{Zero} | \ket{\psi}) = + /// \braket{\psi | 0} \braket{0 | \psi}. + /// \end{align} + /// + /// # Input + /// ## qubit + /// Qubit to be measured. + /// + /// # Output + /// `Zero` if the $+1$ eigenvalue is observed, and `One` if + /// the $-1$ eigenvalue is observed. + /// + /// # Remarks + /// Equivalent to: + /// ```qsharp + /// Measure([PauliZ], [qubit]); + /// ``` + @TargetInstruction("m__body") + internal operation MZ (qubit : Qubit) : Result { + body intrinsic; + } +} \ No newline at end of file diff --git a/src/Simulation/TargetDefinitions/TargetPackages/Type1.Package.props b/src/Simulation/TargetDefinitions/TargetPackages/Type1.Package.props index 6f5210bc054..866fd1f0391 100644 --- a/src/Simulation/TargetDefinitions/TargetPackages/Type1.Package.props +++ b/src/Simulation/TargetDefinitions/TargetPackages/Type1.Package.props @@ -17,7 +17,7 @@ - + @@ -35,6 +35,7 @@ + diff --git a/src/Simulation/TargetDefinitions/TargetPackages/Type3.Package.props b/src/Simulation/TargetDefinitions/TargetPackages/Type3.Package.props index 9baa2e567f5..b0d5d34c908 100644 --- a/src/Simulation/TargetDefinitions/TargetPackages/Type3.Package.props +++ b/src/Simulation/TargetDefinitions/TargetPackages/Type3.Package.props @@ -18,7 +18,7 @@ - + @@ -36,6 +36,7 @@ + diff --git a/src/Simulation/qdk_sim_rs/src/c_api.rs b/src/Simulation/qdk_sim_rs/src/c_api.rs index bf88c09065e..caab540f118 100644 --- a/src/Simulation/qdk_sim_rs/src/c_api.rs +++ b/src/Simulation/qdk_sim_rs/src/c_api.rs @@ -101,7 +101,7 @@ pub extern "C" fn lasterr() -> *const c_char { /// - **`pure`**: Creates the simulator with an initial state represented by /// a state vector. /// - **`mixed`**: Creates the simulator with an initial state represented by -/// a density operat. +/// a density operator. /// - **`stabilizer`**: Creates the simulator with an initial state represented by /// a stabilizer tableau. /// diff --git a/src/Simulation/qdk_sim_rs/src/processes/apply.rs b/src/Simulation/qdk_sim_rs/src/processes/apply.rs index 21de1e77060..cd5cca76b5a 100644 --- a/src/Simulation/qdk_sim_rs/src/processes/apply.rs +++ b/src/Simulation/qdk_sim_rs/src/processes/apply.rs @@ -27,9 +27,9 @@ impl Process { } match &self.data { - Unitary(u) => apply_unitary(&u, state), - KrausDecomposition(ks) => apply_kraus_decomposition(&ks, state), - MixedPauli(paulis) => apply_pauli_channel(&paulis, state), + Unitary(u) => apply_unitary(u, state), + KrausDecomposition(ks) => apply_kraus_decomposition(ks, state), + MixedPauli(paulis) => apply_pauli_channel(paulis, state), Sequence(processes) => { // TODO[perf]: eliminate the extraneous clone here. let mut acc_state = state.clone(); diff --git a/src/Simulation/qdk_sim_rs/src/states.rs b/src/Simulation/qdk_sim_rs/src/states.rs index 3bf69611212..71f36e51b6b 100644 --- a/src/Simulation/qdk_sim_rs/src/states.rs +++ b/src/Simulation/qdk_sim_rs/src/states.rs @@ -162,7 +162,7 @@ impl Trace for &State { fn trace(self) -> Self::Output { match &self.data { Pure(_) | StateData::Stabilizer(_) => C64::one(), - Mixed(ref rho) => (&rho).trace(), + Mixed(ref rho) => rho.trace(), } } }