From e0246360ddbb8d3dc4005171b362549d008e5fc1 Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Fri, 15 Oct 2021 17:24:48 -0700 Subject: [PATCH 1/4] Use explicit static VC runtime on Windows (#851) * Use explicit static VC runtime on Windows This change updates the QIR runtime to use an explicit path to the Spectre-mitigated, static VC runtime on Windows. Using a full path here overrides the selection logic and ensures the chosen libcmt[d] and vcruntime[d] are loaded. * Add "-sort" flag * Include version number in find pattern * Include libcpmt library as well * Use spectre component name --- src/Qir/Runtime/CMakeLists.txt | 41 +++++++++++++++++++ src/Qir/Runtime/lib/QIR/CMakeLists.txt | 1 + src/Qir/Runtime/lib/QSharpCore/CMakeLists.txt | 1 + .../lib/QSharpFoundation/CMakeLists.txt | 1 + src/Qir/Runtime/lib/Tracer/CMakeLists.txt | 1 + 5 files changed, 45 insertions(+) diff --git a/src/Qir/Runtime/CMakeLists.txt b/src/Qir/Runtime/CMakeLists.txt index 3c3c109b019..0635bcf57b2 100644 --- a/src/Qir/Runtime/CMakeLists.txt +++ b/src/Qir/Runtime/CMakeLists.txt @@ -17,6 +17,47 @@ if (NOT APPLE) endif() if (WIN32) + # Enforce use of static runtime (avoids target machine needing msvcrt installed). + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") + + # Locate the vswhere application, which will provide paths to any installed Visual Studio instances. + # By invoking it with "-find **/lib/spectre/x64" we will find any Spectre mitigated libaries that + # have been installed. + find_program(_vswhere_tool + NAMES vswhere + PATHS "$ENV{ProgramFiles\(x86\)}/Microsoft Visual Studio/Installer") + if (NOT ${vswhere}) + message(FATAL_ERROR "Could not locate vswhere.exe - unable to source vc redistributable") + endif() + execute_process( + COMMAND "${_vswhere_tool}" -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -find **/14.29.*/**/lib/spectre/x64 -sort + OUTPUT_VARIABLE _vs_install_loc_out + RESULT_VARIABLE _vs_where_exitcode + OUTPUT_STRIP_TRAILING_WHITESPACE) + file(TO_CMAKE_PATH "${_vs_install_loc_out}" SPECTRE_LIB_PATH_OUT) + string(REGEX REPLACE "[\r\n]+" ";" SPECTRE_LIB_PATH ${SPECTRE_LIB_PATH_OUT}) + message(INFO "*** install loc: ${SPECTRE_LIB_PATH}") + + # Locate the spectre mitigated runtime libraries and fail if they can't be found. Targets in this + # cmake project can use the variables to explicitly link these libraries rather than using the + # non-mitigated libraries that are found by default. + find_library(LIBCMT_SPECTRE_REL libcmt PATHS ${SPECTRE_LIB_PATH} REQUIRED) + find_library(LIBCMT_SPECTRE_DEB libcmtd PATHS ${SPECTRE_LIB_PATH} REQUIRED) + set(LIBCMT_SPECTRE debug ${LIBCMT_SPECTRE_DEB} optimized ${LIBCMT_SPECTRE_REL}) + message(INFO "*** using spectre lib: ${LIBCMT_SPECTRE}") + find_library(LIBCPMT_SPECTRE_REL libcpmt PATHS ${SPECTRE_LIB_PATH} REQUIRED) + find_library(LIBCPMT_SPECTRE_DEB libcpmtd PATHS ${SPECTRE_LIB_PATH} REQUIRED) + set(LIBCPMT_SPECTRE debug ${LIBCPMT_SPECTRE_DEB} optimized ${LIBCPMT_SPECTRE_REL}) + message(INFO "*** using spectre lib: ${LIBCPMT_SPECTRE}") + find_library(LIBVCRUNTIME_SPECTRE_REL libvcruntime PATHS ${SPECTRE_LIB_PATH} REQUIRED) + find_library(LIBVCRUNTIME_SPECTRE_DEB libvcruntimed PATHS ${SPECTRE_LIB_PATH} REQUIRED) + set(LIBVCRUNTIME_SPECTRE debug ${LIBVCRUNTIME_SPECTRE_DEB} optimized ${LIBVCRUNTIME_SPECTRE_REL}) + message(INFO "*** using spectre lib: ${LIBVCRUNTIME_SPECTRE}") + set(SPECTRE_LIBS + ${LIBCMT_SPECTRE} + ${LIBCPMT_SPECTRE} + ${LIBVCRUNTIME_SPECTRE}) + add_link_options("LINKER:/guard:cf") endif() diff --git a/src/Qir/Runtime/lib/QIR/CMakeLists.txt b/src/Qir/Runtime/lib/QIR/CMakeLists.txt index f7ef19d24ed..8fcb15d7c04 100644 --- a/src/Qir/Runtime/lib/QIR/CMakeLists.txt +++ b/src/Qir/Runtime/lib/QIR/CMakeLists.txt @@ -43,6 +43,7 @@ add_library(Microsoft.Quantum.Qir.Runtime SHARED) target_link_libraries(Microsoft.Quantum.Qir.Runtime ${CMAKE_DL_LIBS} qir-rt-support-obj + ${SPECTRE_LIBS} ) target_include_directories(Microsoft.Quantum.Qir.Runtime PUBLIC ${public_includes}) diff --git a/src/Qir/Runtime/lib/QSharpCore/CMakeLists.txt b/src/Qir/Runtime/lib/QSharpCore/CMakeLists.txt index d3fe9170f9f..7bd86a74662 100644 --- a/src/Qir/Runtime/lib/QSharpCore/CMakeLists.txt +++ b/src/Qir/Runtime/lib/QSharpCore/CMakeLists.txt @@ -27,6 +27,7 @@ target_link_libraries(Microsoft.Quantum.Qir.QSharp.Core simulators-obj "-L${CMAKE_BINARY_DIR}/lib/QIR" -lMicrosoft.Quantum.Qir.Runtime + ${SPECTRE_LIBS} ) add_dependencies(Microsoft.Quantum.Qir.QSharp.Core Microsoft.Quantum.Qir.Runtime) diff --git a/src/Qir/Runtime/lib/QSharpFoundation/CMakeLists.txt b/src/Qir/Runtime/lib/QSharpFoundation/CMakeLists.txt index 744d94c86a1..177ec7f4985 100644 --- a/src/Qir/Runtime/lib/QSharpFoundation/CMakeLists.txt +++ b/src/Qir/Runtime/lib/QSharpFoundation/CMakeLists.txt @@ -30,6 +30,7 @@ target_link_libraries(Microsoft.Quantum.Qir.QSharp.Foundation qsharp-foundation-qis-support-obj "-L${CMAKE_BINARY_DIR}/lib/QIR" -lMicrosoft.Quantum.Qir.Runtime + ${SPECTRE_LIBS} ) add_dependencies(Microsoft.Quantum.Qir.QSharp.Foundation Microsoft.Quantum.Qir.Runtime) diff --git a/src/Qir/Runtime/lib/Tracer/CMakeLists.txt b/src/Qir/Runtime/lib/Tracer/CMakeLists.txt index 8ef274e87ef..a28bd52a0d3 100644 --- a/src/Qir/Runtime/lib/Tracer/CMakeLists.txt +++ b/src/Qir/Runtime/lib/Tracer/CMakeLists.txt @@ -25,6 +25,7 @@ target_link_libraries(Microsoft.Quantum.Qir.Tracer tracer-obj "-L${CMAKE_BINARY_DIR}/lib/QIR" -lMicrosoft.Quantum.Qir.Runtime + ${SPECTRE_LIBS} ) add_dependencies(Microsoft.Quantum.Qir.QSharp.Foundation Microsoft.Quantum.Qir.Runtime) From b2e2f80c263adce173e8a6a853cabeb0db9795a9 Mon Sep 17 00:00:00 2001 From: XField <58103249+vxfield@users.noreply.github.com> Date: Wed, 20 Oct 2021 23:44:17 -0700 Subject: [PATCH 2/4] Append AppId to UserAgent when calling Azure Quantum APIs (#858) --- .../WorkspaceTest.cs | 98 ++++++++++++++++++- .../JobManagement/Workspace.cs | 38 ++++++- .../EntryPointDriver.Tests/Tests.fs | 11 +-- .../EntryPointDriver/Azure/AzureSettings.cs | 23 ++--- 4 files changed, 147 insertions(+), 23 deletions(-) diff --git a/src/Azure/Azure.Quantum.Client.Test/WorkspaceTest.cs b/src/Azure/Azure.Quantum.Client.Test/WorkspaceTest.cs index 9f8a6935233..ecca60b212c 100644 --- a/src/Azure/Azure.Quantum.Client.Test/WorkspaceTest.cs +++ b/src/Azure/Azure.Quantum.Client.Test/WorkspaceTest.cs @@ -7,10 +7,12 @@ using System.IO.Compression; using System.Linq; using System.Net; +using System.Reflection; using System.Threading; using System.Threading.Tasks; - +using Azure.Identity; using Azure.Quantum; +using Azure.Quantum.Jobs; using Azure.Quantum.Jobs.Models; using Microsoft.Azure.Quantum.Exceptions; @@ -176,6 +178,100 @@ public async Task ListProviderStatusTest() Assert.AreEqual(0, max); } + [TestMethod] + [TestCategory("Local")] + public async Task ApplicationIdTest() + { + const string ENV_VAR_APPID = "EnvVarAppId"; + const string OPTIONS_APPID = "OptionAppId"; + const string LONG_ENV_VAR_APPID = "LongEnvVarAppId"; + const string LONG_OPTIONS_APPID = "LongOptionAppId"; + const string VERY_LONG_ENV_VAR_APPID = "VeryVeryVeryVeryVeryVeryLongEnvVarAppId"; + const string VERY_LONG_OPTIONS_APPID = "VeryVeryVeryVeryVeryVeryLongOptionAppId"; + const string APPID_ENV_VAR_NAME = "AZURE_QUANTUM_NET_APPID"; + + Func createWorkspace = (QuantumJobClientOptions options) => + { + var credential = new ClientSecretCredential(tenantId: "72f988bf-86f1-41af-91ab-2d7cd011db47", + clientId: "00000000-0000-0000-0000-000000000000", + clientSecret: "PLACEHOLDER"); + return new Workspace(subscriptionId: "SubscriptionId", + resourceGroupName: "ResourceGroupName", + workspaceName: "WorkspaceName", + location: "WestUs", + options: options, + credential: credential); + }; + + var originalEnvironmentAppId = Environment.GetEnvironmentVariable(APPID_ENV_VAR_NAME); + try + { + + // Test with no Environment AppId and no Options AppId + Environment.SetEnvironmentVariable(APPID_ENV_VAR_NAME, null); + var workspace = createWorkspace(null); + Assert.IsNotNull(workspace.ClientOptions); + Assert.IsNotNull(workspace.ClientOptions.Diagnostics); + Assert.AreEqual("", workspace.ClientOptions.Diagnostics.ApplicationId); + + // Test with Environment AppId and no Options AppId + Environment.SetEnvironmentVariable(APPID_ENV_VAR_NAME, ENV_VAR_APPID); + workspace = createWorkspace(null); + Assert.IsNotNull(workspace.ClientOptions); + Assert.IsNotNull(workspace.ClientOptions.Diagnostics); + Assert.AreEqual(ENV_VAR_APPID, workspace.ClientOptions.Diagnostics.ApplicationId); + + // Test with no Environment AppId and with Options AppId + Environment.SetEnvironmentVariable(APPID_ENV_VAR_NAME, null); + var options = new QuantumJobClientOptions(); + options.Diagnostics.ApplicationId = OPTIONS_APPID; + workspace = createWorkspace(options); + Assert.IsNotNull(workspace.ClientOptions); + Assert.IsNotNull(workspace.ClientOptions.Diagnostics); + Assert.AreEqual(OPTIONS_APPID, workspace.ClientOptions.Diagnostics.ApplicationId); + + // Test with Environment AppId and with Options AppId + Environment.SetEnvironmentVariable(APPID_ENV_VAR_NAME, ENV_VAR_APPID); + options = new QuantumJobClientOptions(); + options.Diagnostics.ApplicationId = OPTIONS_APPID; + workspace = createWorkspace(options); + Assert.IsNotNull(workspace.ClientOptions); + Assert.IsNotNull(workspace.ClientOptions.Diagnostics); + Assert.AreEqual($"{OPTIONS_APPID}-{ENV_VAR_APPID}", workspace.ClientOptions.Diagnostics.ApplicationId); + + // Test with long (>24 chars) combination of Environment AppId and Options AppId + Environment.SetEnvironmentVariable(APPID_ENV_VAR_NAME, LONG_ENV_VAR_APPID); + options = new QuantumJobClientOptions(); + options.Diagnostics.ApplicationId = LONG_OPTIONS_APPID; + workspace = createWorkspace(options); + Assert.IsNotNull(workspace.ClientOptions); + Assert.IsNotNull(workspace.ClientOptions.Diagnostics); + var truncatedAppId = $"{LONG_OPTIONS_APPID}-{LONG_ENV_VAR_APPID}".Substring(0, 24); + Assert.AreEqual(truncatedAppId, workspace.ClientOptions.Diagnostics.ApplicationId); + + // Test with long (>24 chars) Environment AppId and no Options AppId + Environment.SetEnvironmentVariable(APPID_ENV_VAR_NAME, VERY_LONG_ENV_VAR_APPID); + workspace = createWorkspace(null); + Assert.IsNotNull(workspace.ClientOptions); + Assert.IsNotNull(workspace.ClientOptions.Diagnostics); + Assert.AreEqual(VERY_LONG_ENV_VAR_APPID.Substring(0, 24), workspace.ClientOptions.Diagnostics.ApplicationId); + + // Test with long (>24 chars) Options AppId and no Environment AppId + Environment.SetEnvironmentVariable(APPID_ENV_VAR_NAME, null); + options = new QuantumJobClientOptions(); + Assert.ThrowsException(() => + options.Diagnostics.ApplicationId = VERY_LONG_OPTIONS_APPID); + } + finally + { + // restore original env var AZURE_QUANTUM_NET_APPID + if (originalEnvironmentAppId != null) + { + Environment.SetEnvironmentVariable(APPID_ENV_VAR_NAME, originalEnvironmentAppId); + } + } + } + private static void AssertJob(CloudJob job) { Assert.IsNotNull(job); diff --git a/src/Azure/Azure.Quantum.Client/JobManagement/Workspace.cs b/src/Azure/Azure.Quantum.Client/JobManagement/Workspace.cs index e4015ee75e8..e431b2fd8ca 100644 --- a/src/Azure/Azure.Quantum.Client/JobManagement/Workspace.cs +++ b/src/Azure/Azure.Quantum.Client/JobManagement/Workspace.cs @@ -10,7 +10,6 @@ namespace Microsoft.Azure.Quantum using System.Threading; using System.Threading.Tasks; using global::Azure.Core; - using global::Azure.Identity; using global::Azure.Quantum; using global::Azure.Quantum.Jobs; using global::Azure.Quantum.Jobs.Models; @@ -50,9 +49,10 @@ public Workspace( // Optional parameters: credential ??= CredentialFactory.CreateCredential(CredentialType.Default, subscriptionId); - options ??= new QuantumJobClientOptions(); - options.Diagnostics.ApplicationId = options.Diagnostics.ApplicationId - ?? Environment.GetEnvironmentVariable("AZURE_QUANTUM_NET_APPID"); + + // Make sure use the property Setter as we have some logic + // tto apply here + this.ClientOptions = options; this.ResourceGroupName = resourceGroupName; this.WorkspaceName = workspaceName; @@ -65,7 +65,7 @@ public Workspace( workspaceName, location, credential, - options); + this.ClientOptions); } public string ResourceGroupName { get; } @@ -81,6 +81,34 @@ public Workspace( /// public QuantumJobClient Client { get; } + /// + /// The options used to create the client to communicate with the service. + /// + public QuantumJobClientOptions ClientOptions + { + get => this.clientOptions; + set + { + // Set the ApplicationId that will be added as a UserAgent prefix + // in calls to the Azure Quantum API. + var applicationId = string.Join('-', + value?.Diagnostics?.ApplicationId?.Trim(), + Environment.GetEnvironmentVariable("AZURE_QUANTUM_NET_APPID")?.Trim() + )?.Trim('-', ' '); + if (applicationId?.Length > 24) + { + applicationId = applicationId?.Substring(0, 24); + } + + value ??= new QuantumJobClientOptions(); + value.Diagnostics.ApplicationId = applicationId; + + this.clientOptions = value; + } + } + + private QuantumJobClientOptions clientOptions; + /// /// Submits the job. /// diff --git a/src/Simulation/EntryPointDriver.Tests/Tests.fs b/src/Simulation/EntryPointDriver.Tests/Tests.fs index 58037e52f0e..1e00e8bd15b 100644 --- a/src/Simulation/EntryPointDriver.Tests/Tests.fs +++ b/src/Simulation/EntryPointDriver.Tests/Tests.fs @@ -646,7 +646,7 @@ let ``Submit allows overriding default values`` () = https://www.example.com/00000000-0000-0000-0000-0000000000000" - + [] let ``Submit allows a long user-agent`` () = let given = test "Returns Unit" @@ -661,7 +661,7 @@ let ``Submit allows a long user-agent`` () = "--shots" "750" "--user-agent" - "a-very-long-user-agent-(it-will-be-truncated)" + "a-very-long-user-agent-(it-will-be-not-be-truncated-here)" "--credential" "cli" ]) @@ -674,18 +674,17 @@ let ``Submit allows a long user-agent`` () = Location: myLocation Credential: CLI AadToken: myTok - UserAgent: a-very-long-user-agent-( + UserAgent: a-very-long-user-agent-(it-will-be-not-be-truncated-here) Job Name: myJobName Job Parameters: Shots: 750 Output: FriendlyUri Dry Run: False Verbose: True - Submitting Q# entry point using a quantum machine. - https://www.example.com/00000000-0000-0000-0000-0000000000000" - + + [] let ``Submit extracts the location from a quantum endpoint`` () = let given = test "Returns Unit" diff --git a/src/Simulation/EntryPointDriver/Azure/AzureSettings.cs b/src/Simulation/EntryPointDriver/Azure/AzureSettings.cs index 87dedafc164..3577d5258f6 100644 --- a/src/Simulation/EntryPointDriver/Azure/AzureSettings.cs +++ b/src/Simulation/EntryPointDriver/Azure/AzureSettings.cs @@ -136,19 +136,20 @@ internal TokenCredential CreateCredentials() } } - internal string? TrimmedUserAgent() { - var userAgent = (UserAgent ?? System.Environment.GetEnvironmentVariable("USER_AGENT"))?.Trim(); - - return (userAgent == null || userAgent.Length < 25) - ? userAgent - : userAgent.Substring(0, 24); - } - - internal QuantumJobClientOptions CreateClientOptions() { var options = new QuantumJobClientOptions(); - options.Diagnostics.ApplicationId = TrimmedUserAgent(); + + // This value will be added as a prefix in the UserAgent when + // calling the Azure Quantum API + // It cannot be larger than 24 characters. + var applicationId = string.Join('@', "Q#Run", UserAgent?.Trim()).Trim(' ', '@'); + if (applicationId?.Length > 24) + { + applicationId = applicationId.Substring(0, 24); + } + + options.Diagnostics.ApplicationId = applicationId; return options; } @@ -187,7 +188,7 @@ public override string ToString() => string.Join( $"Location: {Location ?? ExtractLocation(BaseUri)}", $"Credential: {Credential}", $"AadToken: {AadToken?.Substring(0, 5)}", - $"UserAgent: {TrimmedUserAgent()}", + $"UserAgent: {UserAgent}", $"Job Name: {JobName}", $"Job Parameters: {string.Join(", ", JobParams.OrderBy(item => item.Key))}", $"Shots: {Shots}", From 1702325887853b83ede761117f7b20c7dd346a19 Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Tue, 26 Oct 2021 23:10:05 -0700 Subject: [PATCH 3/4] Add `CX`, `CY` and `CZ` to Type1, Type3 target packages. (#842) (#861) --- .../Decompositions/CCNOTFromCCZ.qs | 2 +- .../TargetDefinitions/Decompositions/CX.qs | 42 ++++++++++++++++ .../Decompositions/CYFromCNOT.qs | 46 +++++++++++++++++ .../Decompositions/CZFromSinglyControlled.qs | 50 +++++++++++++++++++ .../TargetDefinitions/Decompositions/Utils.qs | 17 +++++++ .../Decompositions/YFromSinglyControlled.qs | 10 ++-- .../Decompositions/ZFromSinglyControlled.qs | 16 +----- .../TargetPackages/Type1.Package.props | 3 ++ .../TargetPackages/Type3.Package.props | 3 ++ 9 files changed, 167 insertions(+), 22 deletions(-) create mode 100644 src/Simulation/TargetDefinitions/Decompositions/CX.qs create mode 100644 src/Simulation/TargetDefinitions/Decompositions/CYFromCNOT.qs create mode 100644 src/Simulation/TargetDefinitions/Decompositions/CZFromSinglyControlled.qs diff --git a/src/Simulation/TargetDefinitions/Decompositions/CCNOTFromCCZ.qs b/src/Simulation/TargetDefinitions/Decompositions/CCNOTFromCCZ.qs index fcc55c6aaa6..f9082d9e2ee 100644 --- a/src/Simulation/TargetDefinitions/Decompositions/CCNOTFromCCZ.qs +++ b/src/Simulation/TargetDefinitions/Decompositions/CCNOTFromCCZ.qs @@ -26,7 +26,7 @@ namespace Microsoft.Quantum.Intrinsic { H(target); } apply { - Controlled Z([control1, control2], target); + CCZ(control1, control2, target); } } controlled (ctls, ...) { diff --git a/src/Simulation/TargetDefinitions/Decompositions/CX.qs b/src/Simulation/TargetDefinitions/Decompositions/CX.qs new file mode 100644 index 00000000000..f212bb3eced --- /dev/null +++ b/src/Simulation/TargetDefinitions/Decompositions/CX.qs @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Canon { + open Microsoft.Quantum.Intrinsic; + + /// # Summary + /// Applies the controlled-X (CX) gate to a pair of qubits. + /// + /// # Description + /// This operation can be simulated by the unitary matrix + /// $$ + /// \begin{align} + /// \left(\begin{matrix} + /// 1 & 0 & 0 & 0 \\\\ + /// 0 & 1 & 0 & 0 \\\\ + /// 0 & 0 & 0 & 1 \\\\ + /// 0 & 0 & 1 & 0 + /// \end{matrix}\right) + /// \end{align}, + /// $$ + /// where rows and columns are organized as in the quantum concepts guide. + /// + /// # Input + /// ## control + /// Control qubit for the CX gate. + /// ## target + /// Target qubit for the CX gate. + /// + /// # Remarks + /// Equivalent to: + /// ```qsharp + /// Controlled X([control], target); + /// ``` + /// and to: + /// ```qsharp + /// CNOT(control, target); + /// ``` + operation CX(control : Qubit, target : Qubit) : Unit is Adj + Ctl{ + CNOT(control, target); + } +} \ No newline at end of file diff --git a/src/Simulation/TargetDefinitions/Decompositions/CYFromCNOT.qs b/src/Simulation/TargetDefinitions/Decompositions/CYFromCNOT.qs new file mode 100644 index 00000000000..364b4d2c573 --- /dev/null +++ b/src/Simulation/TargetDefinitions/Decompositions/CYFromCNOT.qs @@ -0,0 +1,46 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Canon { + open Microsoft.Quantum.Intrinsic; + + /// # Summary + /// Applies the controlled-Y (CY) gate to a pair of qubits. + /// + /// # Description + /// This operation can be simulated by the unitary matrix + /// $$ + /// \begin{align} + /// 1 & 0 & 0 & 0 \\\\ + /// 0 & 1 & 0 & 0 \\\\ + /// 0 & 0 & 0 & -i \\\\ + /// 0 & 0 & i & 0 + /// \end{align}, + /// $$ + /// where rows and columns are organized as in the quantum concepts guide. + /// + /// # Input + /// ## control + /// Control qubit for the CY gate. + /// ## target + /// Target qubit for the CY gate. + /// + /// # Remarks + /// Equivalent to: + /// ```qsharp + /// Controlled Y([control], target); + /// ``` + operation CY(control : Qubit, target : Qubit) : Unit { + body (...) { + within { + MapPauli(target, PauliX, PauliY); + } + apply { + CNOT(control, target); + } + } + adjoint self; + controlled distribute; + controlled adjoint self; + } +} \ No newline at end of file diff --git a/src/Simulation/TargetDefinitions/Decompositions/CZFromSinglyControlled.qs b/src/Simulation/TargetDefinitions/Decompositions/CZFromSinglyControlled.qs new file mode 100644 index 00000000000..80d6000368e --- /dev/null +++ b/src/Simulation/TargetDefinitions/Decompositions/CZFromSinglyControlled.qs @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Canon { + open Microsoft.Quantum.Intrinsic; + + /// # Summary + /// Applies the controlled-Z (CZ) gate to a pair of qubits. + /// + /// # Description + /// This operation can be simulated by the unitary matrix + /// $$ + /// \begin{align} + /// 1 & 0 & 0 & 0 \\\\ + /// 0 & 1 & 0 & 0 \\\\ + /// 0 & 0 & 1 & 0 \\\\ + /// 0 & 0 & 0 & -1 + /// \end{align}, + /// $$ + /// where rows and columns are organized as in the quantum concepts guide. + /// + /// # Input + /// ## control + /// Control qubit for the CZ gate. + /// ## target + /// Target qubit for the CZ gate. + /// + /// # Remarks + /// Equivalent to: + /// ```qsharp + /// Controlled Z([control], target); + /// ``` + operation CZ(control : Qubit, target : Qubit) : Unit { + body (...) { + ApplyControlledZ(control, target); + } + controlled (ctls, ...) { + if Length(ctls) == 0 { + ApplyControlledZ(control, target); + } + elif Length(ctls) == 1 { + CCZ(ctls[0], control, target); + } + else { + ApplyWithLessControlsA(Controlled CZ, (ctls, (control, target))); + } + } + adjoint self; + } +} \ No newline at end of file diff --git a/src/Simulation/TargetDefinitions/Decompositions/Utils.qs b/src/Simulation/TargetDefinitions/Decompositions/Utils.qs index 32c31472a42..3275be341a0 100644 --- a/src/Simulation/TargetDefinitions/Decompositions/Utils.qs +++ b/src/Simulation/TargetDefinitions/Decompositions/Utils.qs @@ -99,6 +99,23 @@ namespace Microsoft.Quantum.Intrinsic { H(target); } + internal operation CCZ (control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj { + // [Page 15 of arXiv:1206.0758v3](https://arxiv.org/pdf/1206.0758v3.pdf#page=15) + Adjoint T(control1); + Adjoint T(control2); + CNOT(target, control1); + T(control1); + CNOT(control2, target); + CNOT(control2, control1); + T(target); + Adjoint T(control1); + CNOT(control2, target); + CNOT(target, control1); + Adjoint T(target); + T(control1); + CNOT(control2, control1); + } + internal function ReducedDyadicFraction (numerator : Int, denominatorPowerOfTwo : Int) : (Int, Int) { if (numerator == 0) { return (0,0); } mutable num = numerator; diff --git a/src/Simulation/TargetDefinitions/Decompositions/YFromSinglyControlled.qs b/src/Simulation/TargetDefinitions/Decompositions/YFromSinglyControlled.qs index 71499ff03ac..95e0cb96740 100644 --- a/src/Simulation/TargetDefinitions/Decompositions/YFromSinglyControlled.qs +++ b/src/Simulation/TargetDefinitions/Decompositions/YFromSinglyControlled.qs @@ -2,6 +2,7 @@ // Licensed under the MIT License. namespace Microsoft.Quantum.Intrinsic { + open Microsoft.Quantum.Canon; /// # Summary /// Applies the Pauli $Y$ gate. @@ -27,19 +28,14 @@ namespace Microsoft.Quantum.Intrinsic { ApplyUncontrolledY(qubit); } elif (Length(ctls) == 1) { - within { - MapPauli(qubit, PauliX, PauliY); - } - apply { - CNOT(ctls[0], qubit); - } + CY(ctls[0], qubit); } elif (Length(ctls) == 2) { within { MapPauli(qubit, PauliZ, PauliY); } apply { - Controlled Z(ctls, qubit); + CCZ(ctls[0], ctls[1], qubit); } } else { diff --git a/src/Simulation/TargetDefinitions/Decompositions/ZFromSinglyControlled.qs b/src/Simulation/TargetDefinitions/Decompositions/ZFromSinglyControlled.qs index 7072a4f17c9..52b8f7d7b00 100644 --- a/src/Simulation/TargetDefinitions/Decompositions/ZFromSinglyControlled.qs +++ b/src/Simulation/TargetDefinitions/Decompositions/ZFromSinglyControlled.qs @@ -2,6 +2,7 @@ // Licensed under the MIT License. namespace Microsoft.Quantum.Intrinsic { + open Microsoft.Quantum.Canon; /// # Summary /// Applies the Pauli $Z$ gate. @@ -30,20 +31,7 @@ namespace Microsoft.Quantum.Intrinsic { ApplyControlledZ(ctls[0], qubit); } elif (Length(ctls) == 2) { - // [Page 15 of arXiv:1206.0758v3](https://arxiv.org/pdf/1206.0758v3.pdf#page=15) - Adjoint T(ctls[0]); - Adjoint T(ctls[1]); - CNOT(qubit, ctls[0]); - T(ctls[0]); - CNOT(ctls[1], qubit); - CNOT(ctls[1], ctls[0]); - T(qubit); - Adjoint T(ctls[0]); - CNOT(ctls[1], qubit); - CNOT(qubit, ctls[0]); - Adjoint T(qubit); - T(ctls[0]); - CNOT(ctls[1], ctls[0]); + CCZ(ctls[0], ctls[1], qubit); } else { ApplyWithLessControlsA(Controlled Z, (ctls, qubit)); diff --git a/src/Simulation/TargetDefinitions/TargetPackages/Type1.Package.props b/src/Simulation/TargetDefinitions/TargetPackages/Type1.Package.props index 866fd1f0391..a66eb655be5 100644 --- a/src/Simulation/TargetDefinitions/TargetPackages/Type1.Package.props +++ b/src/Simulation/TargetDefinitions/TargetPackages/Type1.Package.props @@ -26,6 +26,9 @@ + + + diff --git a/src/Simulation/TargetDefinitions/TargetPackages/Type3.Package.props b/src/Simulation/TargetDefinitions/TargetPackages/Type3.Package.props index b0d5d34c908..3dd8eee8145 100644 --- a/src/Simulation/TargetDefinitions/TargetPackages/Type3.Package.props +++ b/src/Simulation/TargetDefinitions/TargetPackages/Type3.Package.props @@ -27,6 +27,9 @@ + + + From 9239c4200ba2feb31e50c2e666c2feec96403b15 Mon Sep 17 00:00:00 2001 From: Ian Davis Date: Thu, 4 Nov 2021 17:11:19 -0700 Subject: [PATCH 4/4] Moving QIR runtime build config into CMakeLists. (#863) * Moving QIR runtime build config into qir_cmake_include CMakeLists. --- src/Qir/Common/cmake/qir_cmake_include.cmake | 169 ++++++++++++++++++ src/Qir/Runtime/CMakeLists.txt | 7 - src/Qir/qir-utils.ps1 | 174 ++----------------- 3 files changed, 184 insertions(+), 166 deletions(-) diff --git a/src/Qir/Common/cmake/qir_cmake_include.cmake b/src/Qir/Common/cmake/qir_cmake_include.cmake index 25e66fbd104..9ad60d716ea 100644 --- a/src/Qir/Common/cmake/qir_cmake_include.cmake +++ b/src/Qir/Common/cmake/qir_cmake_include.cmake @@ -39,3 +39,172 @@ macro(target_source_from_qir target_name source_file) ${OBJFILE} ) endmacro() + + +#=============================================================================== +# Common flags + +# Always use available Spectre mitigations where available +if (NOT APPLE) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mspeculative-load-hardening -mretpoline") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mspeculative-load-hardening -mretpoline") +endif() + +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG") +set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DDEBUG") + +#=============================================================================== +# Warnings + +# Treat warnings as errors: +# https://clang.llvm.org/docs/UsersManual.html#options-to-control-error-and-warning-messages +set(WARNING_FLAGS "-Werror") + +# Enable all warnings: +# https://clang.llvm.org/docs/UsersManual.html#enabling-all-diagnostics +# https://clang.llvm.org/docs/DiagnosticsReference.html +set(WARNING_FLAGS "${WARNING_FLAGS} -Weverything") + +# Disable these warnings: + +# We don't care about keeping compatibility with C++98/03, C++11, C++14. Any new features unknown to our compiler version will be reported as errors. +# -Wc++98-compat-pedantic +# -Wc++98-compat, +# -Wc++98-compat-local-type-template-args, -Wc++98-compat-unnamed-type-template-args, -Wpre-c++14-compat, +# -Wpre-c++17-compat, -Wpre-c++20-compat, -Wpre-c++2b-compat. +# -Wc++98-compat-bind-to-temporary-copy, -Wc++98-compat-extra-semi, +# -Wpre-c++14-compat-pedantic, +# -Wc++98-c++11-compat-binary-literal, -Wpre-c++14-compat. +# -Wpre-c++17-compat-pedantic, +# -Wpre-c++17-compat. +# -Wpre-c++20-compat-pedantic, +# -Wpre-c++20-compat. +# -Wpre-c++2b-compat-pedantic (= -Wpre-c++2b-compat). + +# https://clang.llvm.org/docs/DiagnosticsReference.html#wc-98-compat-pedantic +set(WARNING_FLAGS "${WARNING_FLAGS} -Wno-c++98-compat-pedantic") + +# Old-style casts increase readability as opposed to `reinterpret_cast<..>()`. We want to be able to use the old-style casts. +set(WARNING_FLAGS "${WARNING_FLAGS} -Wno-old-style-cast") + +# Even if the `switch` covers all the enumerators, it is still good to have `default` label to cover the potential newly added (but not handled) enumerators. +set(WARNING_FLAGS "${WARNING_FLAGS} -Wno-covered-switch-default") + +# We are OK using C99 features. +# -Wc99-extension +# -Wc99-designator +# -Wc++20-designator +set(WARNING_FLAGS "${WARNING_FLAGS} -Wno-c99-extensions") + +# We are OK that the structs are padded to align the fields. +# https://clang.llvm.org/docs/DiagnosticsReference.html#wpadded +set(WARNING_FLAGS "${WARNING_FLAGS} -Wno-padded") + +# We are OK with abstract classes. +set(WARNING_FLAGS "${WARNING_FLAGS} -Wno-weak-vtables") + +# Temporarily disable the following warnings (until QIR RT is refactored to expose C interface). + +# Looks like the `-Wglobal-constructors` warns that the instance of the `__dllexport` class/struct (or a static member var of such class/struct) +# needs to be constructible by calling a global `__dllexport` function (to guarantee that a single instance is created and the same instance is used +# both inside and outside of the binary (dynamic library or executable)). +# Or it warns about the constructor that is invoked for a global (or static member) variable _before_ the `main()` is invoked, thus slowing down the start, +# see https://stackoverflow.com/a/15708829/6362941 + +# https://clang.llvm.org/docs/DiagnosticsReference.html#wglobal-constructors +set(WARNING_FLAGS "${WARNING_FLAGS} -Wno-global-constructors") + +# Looks like the `-Wexit-time-destructors` warns that the destructor of a global or static member variable will be invoked +# _after_ the `main()` returns (thus slowing down the termination/restart). +set(WARNING_FLAGS "${WARNING_FLAGS} -Wno-exit-time-destructors") + +# Temporarily disable "-Wextra-semi-stmt" that warns about redundant `;` in the end of `INFO(id);` of Catch tests framework (which looks fixed in the latest Catch version). +# Disable until the Catch header "src\Qir\Common\Externals\catch2\catch.hpp" is updated to a version newer than v2.12.1 (from https://github.com/catchorg/Catch2). + +# https://clang.llvm.org/docs/DiagnosticsReference.html#wextra-semi-stmt +set(WARNING_FLAGS "${WARNING_FLAGS} -Wno-extra-semi-stmt") + +# Save the assembled warnings +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNING_FLAGS}") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WARNING_FLAGS}") + + +#=============================================================================== +# Sanitizers (https://clang.llvm.org/docs/UsersManual.html#controlling-code-generation): + +if (NOT WIN32) + set(SANITIZE_FLAGS "") + + # Undefined Behavior Sanitizer (https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html) + # Win: + # FAILED: lib/QIR/Microsoft.Quantum.Qir.Runtime.dll lib/QIR/Microsoft.Quantum.Qir.Runtime.lib + # lld-link: error: /failifmismatch: mismatch detected for 'RuntimeLibrary': + # >>> lib/QIR/CMakeFiles/qir-rt-support-obj.dir/QubitManager.cpp.obj has value MD_DynamicRelease + # >>> clang_rt.ubsan_standalone_cxx-x86_64.lib(ubsan_type_hash_win.cc.obj) has value MT_StaticRelease + # clang++: error: linker command failed with exit code 1 (use -v to see invocation) + set(SANITIZE_FLAGS "${SANITIZE_FLAGS} -fsanitize=undefined -fsanitize=float-divide-by-zero -fsanitize=unsigned-integer-overflow -fsanitize=implicit-conversion -fsanitize=local-bounds -fsanitize=nullability") + + # TODO: + # For Win consider extra build configuration linking all libs statically, enable `-fsanitize=undefined`, run the statically linked tests. + + #if (-not ($IsMacOS)) # Cannot be combined with `-fsanitize=address`. + #{ + # # Safe Stack instrumentation (https://clang.llvm.org/docs/SafeStack.html): + # # No support for Win, Mac. + # # clang: error: unsupported option '-fsanitize=safe-stack' for target 'x86_64-apple-darwin19.6.0' + # # Linking a DSO with SafeStack is not currently supported. But compilation, linking, and test runs all succeed. + # $sanitizeFlags += " -fsanitize=safe-stack" + #} + + ## Memory Sanitizer (https://clang.llvm.org/docs/MemorySanitizer.html) + ## Win: Not supported. + ## clang: error: unsupported option '-fsanitize=memory' for target 'x86_64-pc-windows-msvc' + ## WSL: Complains for use-of-uninitialized-value in `catch2/catch.hpp` during initialization of global vars + ## (if run both as `pwsh Runtime/test-qir-runtime.ps1` (or Tests/test-qir-tests.ps1) and as standalone). + ## An update of `catch2/catch.hpp` to 2.13.6 (search for "go to the v2.x branch" at https://github.com/catchorg/Catch2) didn't help. + ## Suppressing of the errors in the updated `catch2/catch.hpp` and standard library headers eventually bumps into errors reported in `memcmp`, + ## suppressing of which does not work (https://github.com/google/sanitizers/issues/1429#issuecomment-876799463). + ## Looks like MSan will not work until the libstdc++ is recompiled to be instrumented (https://clang.llvm.org/docs/MemorySanitizer.html#handling-external-code). + ## Instrumenting libstdc++ during CI builds seems impractical (https://stackoverflow.com/a/22301584/6362941). + #$sanitizeFlags += " -fsanitize=memory -fsanitize-memory-track-origins=2" + + # Address Sanitizer (https://clang.llvm.org/docs/AddressSanitizer.html) + # Win: (Conflict between the ASan library and MSVC library) + # [19/35] Linking CXX shared library lib\QIR\Microsoft.Quantum.Qir.Runtime.dll + # FAILED: lib/QIR/Microsoft.Quantum.Qir.Runtime.dll lib/QIR/Microsoft.Quantum.Qir.Runtime.lib + # cmd.exe /C "cd . && C:\PROGRA~1\LLVM12\bin\CLANG_~1.EXE -fuse-ld=lld-link -nostartfiles -nostdlib -Werror -Weverything .... \ + # -fsanitize=address -g -Xclang -gcodeview -O0 -DDEBUG -D_DEBUG -D_DLL -D_MT -Xclang --dependent-lib=msvcrtd \ + # -Xlinker /guard:cf -shared -o lib\QIR\Microsoft.Quantum.Qir.Runtime.dll -Xlinker /implib:lib\QIR\Microsoft.Quantum.Qir.Runtime.lib \ + # -Xlinker /pdb:lib\QIR\Microsoft.Quantum.Qir.Runtime.pdb -Xlinker /version:0.0 lib/QIR/bridge-rt.obj \ + # lib/QIR/CMakeFiles/qir-rt-support-obj.dir/QirRange.cpp.obj lib/QIR/CMakeFiles/qir-rt-support-obj.dir/OutputStream.cpp.obj ....\ + # -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32 -loldnames && cd ." + # lld-link: error: duplicate symbol: malloc + # >>> defined at C:\src\llvm_package_6923b0a7\llvm-project\compiler-rt\lib\asan\asan_win_dll_thunk.cpp:34 + # >>> clang_rt.asan_dll_thunk-x86_64.lib(asan_win_dll_thunk.cpp.obj) + # >>> defined at ucrtbased.dll + # clang++: error: linker command failed with exit code 1 (use -v to see invocation) + + # https://clang.llvm.org/docs/AddressSanitizer.html + set(SANITIZE_FLAGS "${SANITIZE_FLAGS} -fsanitize=address") + + # TODO: + # * Some tests verify the failure behavior, i.e. they cause `Fail()` to be called and return to the caller with the exception. + # Any allocations made between the call and the exception throw (caught by `REQUIRE_THROWS()`) are leaking. + # Extract such tests to a separate .cpp file or executable and compile with leak check off (or suppress leaks in that .cpp or executable only). + + # Common for all sanitizers: + # https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html#suppressing-errors-in-recompiled-code-ignorelist + # https://releases.llvm.org/11.0.1/tools/clang/docs/SanitizerSpecialCaseList.html + set(SANITIZE_FLAGS "${SANITIZE_FLAGS} -fsanitize-blacklist=${CMAKE_CURRENT_LIST_DIR}/../../UBSan.ignore") + + # https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html + set(SANITIZE_FLAGS "${SANITIZE_FLAGS} -fno-omit-frame-pointer") + + # https://clang.llvm.org/docs/AddressSanitizer.html + set(SANITIZE_FLAGS "${SANITIZE_FLAGS} -fno-optimize-sibling-calls") + + # Save the flags + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${SANITIZE_FLAGS}") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${SANITIZE_FLAGS}") +endif() + diff --git a/src/Qir/Runtime/CMakeLists.txt b/src/Qir/Runtime/CMakeLists.txt index 0635bcf57b2..0f4bdf52d55 100644 --- a/src/Qir/Runtime/CMakeLists.txt +++ b/src/Qir/Runtime/CMakeLists.txt @@ -9,13 +9,6 @@ project(qirruntime) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED True) -set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG") - -# Always use available Spectre mitigations where available -if (NOT APPLE) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mspeculative-load-hardening -mretpoline") -endif() - if (WIN32) # Enforce use of static runtime (avoids target machine needing msvcrt installed). set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") diff --git a/src/Qir/qir-utils.ps1 b/src/Qir/qir-utils.ps1 index 11aac34ecfa..612c19b9246 100644 --- a/src/Qir/qir-utils.ps1 +++ b/src/Qir/qir-utils.ps1 @@ -34,163 +34,24 @@ function Build-CMakeProject { ) Write-Host "##[info]Build $Name" - $oldCC = $env:CC - $oldCXX = $env:CXX - $oldRC = $env:RC - $oldCFLAGS = $env:CFLAGS - $oldCXXFLAGS = $env:CXXFLAGS + $CMAKE_C_COMPILER = "" + $CMAKE_CXX_COMPILER = "" $clangTidy = "" - # Treat warnings as errors: - $warningFlags = "-Werror" # https://clang.llvm.org/docs/UsersManual.html#options-to-control-error-and-warning-messages - # Enable all warnings: - $warningFlags += " -Weverything" # https://clang.llvm.org/docs/UsersManual.html#enabling-all-diagnostics - # https://clang.llvm.org/docs/DiagnosticsReference.html - - # Disable these warnings: - - # We don't care about keeping compatibility with C++98/03, C++11, C++14. Any new features unknown to our compiler version will be reported as errors. - # -Wc++98-compat-pedantic - # -Wc++98-compat, - # -Wc++98-compat-local-type-template-args, -Wc++98-compat-unnamed-type-template-args, -Wpre-c++14-compat, - # -Wpre-c++17-compat, -Wpre-c++20-compat, -Wpre-c++2b-compat. - # -Wc++98-compat-bind-to-temporary-copy, -Wc++98-compat-extra-semi, - # -Wpre-c++14-compat-pedantic, - # -Wc++98-c++11-compat-binary-literal, -Wpre-c++14-compat. - # -Wpre-c++17-compat-pedantic, - # -Wpre-c++17-compat. - # -Wpre-c++20-compat-pedantic, - # -Wpre-c++20-compat. - # -Wpre-c++2b-compat-pedantic (= -Wpre-c++2b-compat). - $warningFlags += " -Wno-c++98-compat-pedantic" # https://clang.llvm.org/docs/DiagnosticsReference.html#wc-98-compat-pedantic - # Old-style casts increase readability as opposed to `reinterpret_cast<..>()`. We want to be able to use the old-style casts. - $warningFlags += " -Wno-old-style-cast" - # Even if the `switch` covers all the enumerators, it is still good to have `default` label to cover the potential newly added (but not handled) enumerators. - $warningFlags += " -Wno-covered-switch-default" - # We are OK using C99 features. - # -Wc99-extension - # -Wc99-designator - # -Wc++20-designator - $warningFlags += " -Wno-c99-extensions" - # We are OK that the structs are padded to align the fields. - $warningFlags += " -Wno-padded" # https://clang.llvm.org/docs/DiagnosticsReference.html#wpadded - # We are OK with abstract classes. - $warningFlags += " -Wno-weak-vtables" - - - # Temporarily disable the following warnings (until QIR RT is refactored to expose C interface). - - # Looks like the `-Wglobal-constructors` warns that the instance of the `__dllexport` class/struct (or a static member var of such class/struct) - # needs to be constructible by calling a global `__dllexport` function (to guarantee that a single instance is created and the same instance is used - # both inside and outside of the binary (dynamic library or executable)). - # Or it warns about the constructor that is invoked for a global (or static member) variable _before_ the `main()` is invoked, thus slowing down the start, - # see https://stackoverflow.com/a/15708829/6362941 - $warningFlags += " -Wno-global-constructors" # https://clang.llvm.org/docs/DiagnosticsReference.html#wglobal-constructors - # Looks like the `-Wexit-time-destructors` warns that the destructor of a global or static member variable will be invoked - # _after_ the `main()` returns (thus slowing down the termination/restart). - $warningFlags += " -Wno-exit-time-destructors" - - # Temporarily disable "-Wextra-semi-stmt" that warns about redundant `;` in the end of `INFO(id);` of Catch tests framework (which looks fixed in the latest Catch version). - # Disable until the Catch header "src\Qir\Common\Externals\catch2\catch.hpp" is updated to a version newer than v2.12.1 (from https://github.com/catchorg/Catch2). - $warningFlags += " -Wno-extra-semi-stmt" # https://clang.llvm.org/docs/DiagnosticsReference.html#wextra-semi-stmt - - $env:CFLAGS += $warningFlags - $env:CXXFLAGS += $warningFlags - - - if ($Env:BUILD_CONFIGURATION -eq "Debug") - { - # Sanitizers (https://clang.llvm.org/docs/UsersManual.html#controlling-code-generation): - - $sanitizeFlags = "" - if (-not ($IsWindows)) - { - # Undefined Behavior Sanitizer (https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html) - # Win: - # FAILED: lib/QIR/Microsoft.Quantum.Qir.Runtime.dll lib/QIR/Microsoft.Quantum.Qir.Runtime.lib - # lld-link: error: /failifmismatch: mismatch detected for 'RuntimeLibrary': - # >>> lib/QIR/CMakeFiles/qir-rt-support-obj.dir/QubitManager.cpp.obj has value MD_DynamicRelease - # >>> clang_rt.ubsan_standalone_cxx-x86_64.lib(ubsan_type_hash_win.cc.obj) has value MT_StaticRelease - # clang++: error: linker command failed with exit code 1 (use -v to see invocation) - $sanitizeFlags += " -fsanitize=undefined -fsanitize=float-divide-by-zero -fsanitize=unsigned-integer-overflow -fsanitize=implicit-conversion -fsanitize=local-bounds -fsanitize=nullability" - # TODO: - # For Win consider extra build configuration linking all libs statically, enable `-fsanitize=undefined`, run the statically linked tests. - - #if (-not ($IsMacOS)) # Cannot be combined with `-fsanitize=address`. - #{ - # # Safe Stack instrumentation (https://clang.llvm.org/docs/SafeStack.html): - # # No support for Win, Mac. - # # clang: error: unsupported option '-fsanitize=safe-stack' for target 'x86_64-apple-darwin19.6.0' - # # Linking a DSO with SafeStack is not currently supported. But compilation, linking, and test runs all succeed. - # $sanitizeFlags += " -fsanitize=safe-stack" - #} - - ## Memory Sanitizer (https://clang.llvm.org/docs/MemorySanitizer.html) - ## Win: Not supported. - ## clang: error: unsupported option '-fsanitize=memory' for target 'x86_64-pc-windows-msvc' - ## WSL: Complains for use-of-uninitialized-value in `catch2/catch.hpp` during initialization of global vars - ## (if run both as `pwsh Runtime/test-qir-runtime.ps1` (or Tests/test-qir-tests.ps1) and as standalone). - ## An update of `catch2/catch.hpp` to 2.13.6 (search for "go to the v2.x branch" at https://github.com/catchorg/Catch2) didn't help. - ## Suppressing of the errors in the updated `catch2/catch.hpp` and standard library headers eventually bumps into errors reported in `memcmp`, - ## suppressing of which does not work (https://github.com/google/sanitizers/issues/1429#issuecomment-876799463). - ## Looks like MSan will not work until the libstdc++ is recompiled to be instrumented (https://clang.llvm.org/docs/MemorySanitizer.html#handling-external-code). - ## Instrumenting libstdc++ during CI builds seems impractical (https://stackoverflow.com/a/22301584/6362941). - #$sanitizeFlags += " -fsanitize=memory -fsanitize-memory-track-origins=2" - - # Address Sanitizer (https://clang.llvm.org/docs/AddressSanitizer.html) - # Win: (Conflict between the ASan library and MSVC library) - # [19/35] Linking CXX shared library lib\QIR\Microsoft.Quantum.Qir.Runtime.dll - # FAILED: lib/QIR/Microsoft.Quantum.Qir.Runtime.dll lib/QIR/Microsoft.Quantum.Qir.Runtime.lib - # cmd.exe /C "cd . && C:\PROGRA~1\LLVM12\bin\CLANG_~1.EXE -fuse-ld=lld-link -nostartfiles -nostdlib -Werror -Weverything .... \ - # -fsanitize=address -g -Xclang -gcodeview -O0 -DDEBUG -D_DEBUG -D_DLL -D_MT -Xclang --dependent-lib=msvcrtd \ - # -Xlinker /guard:cf -shared -o lib\QIR\Microsoft.Quantum.Qir.Runtime.dll -Xlinker /implib:lib\QIR\Microsoft.Quantum.Qir.Runtime.lib \ - # -Xlinker /pdb:lib\QIR\Microsoft.Quantum.Qir.Runtime.pdb -Xlinker /version:0.0 lib/QIR/bridge-rt.obj \ - # lib/QIR/CMakeFiles/qir-rt-support-obj.dir/QirRange.cpp.obj lib/QIR/CMakeFiles/qir-rt-support-obj.dir/OutputStream.cpp.obj ....\ - # -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32 -loldnames && cd ." - # lld-link: error: duplicate symbol: malloc - # >>> defined at C:\src\llvm_package_6923b0a7\llvm-project\compiler-rt\lib\asan\asan_win_dll_thunk.cpp:34 - # >>> clang_rt.asan_dll_thunk-x86_64.lib(asan_win_dll_thunk.cpp.obj) - # >>> defined at ucrtbased.dll - # clang++: error: linker command failed with exit code 1 (use -v to see invocation) - $sanitizeFlags += " -fsanitize=address" # https://clang.llvm.org/docs/AddressSanitizer.html - # TODO: - # * Some tests verify the failure behavior, i.e. they cause `Fail()` to be called and return to the caller with the exception. - # Any allocations made between the call and the exception throw (caught by `REQUIRE_THROWS()`) are leaking. - # Extract such tests to a separate .cpp file or executable and compile with leak check off (or suppress leaks in that .cpp or executable only). - - # Common for all sanitizers: - $sanitizeFlags += " -fsanitize-blacklist=" # https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html#suppressing-errors-in-recompiled-code-ignorelist - # https://releases.llvm.org/11.0.1/tools/clang/docs/SanitizerSpecialCaseList.html - $sanitizeFlags += (Join-Path $Path .. UBSan.ignore) - - $sanitizeFlags += " -fno-omit-frame-pointer" # https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html - $sanitizeFlags += " -fno-optimize-sibling-calls" # https://clang.llvm.org/docs/AddressSanitizer.html - } # if (-not ($IsWindows)) - - $env:CFLAGS += $sanitizeFlags - $env:CXXFLAGS += $sanitizeFlags - } # 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)" } - elseif (($IsLinux) -or ((Test-Path Env:AGENT_OS) -and ($Env:AGENT_OS.StartsWith("Lin")))) - { + elseif (($IsLinux) -or ((Test-Path Env:AGENT_OS) -and ($Env:AGENT_OS.StartsWith("Lin")))) { Write-Host "On Linux build $Name using Clang" - $env:CC = "clang-11" - $env:CXX = "clang++-11" - $env:RC = "clang++-11" + $CMAKE_C_COMPILER = "-DCMAKE_C_COMPILER=clang-11" + $CMAKE_CXX_COMPILER = "-DCMAKE_CXX_COMPILER=clang++-11" $clangTidy = "-DCMAKE_CXX_CLANG_TIDY=clang-tidy-11" } - elseif (($IsWindows) -or ((Test-Path Env:AGENT_OS) -and ($Env:AGENT_OS.StartsWith("Win")))) - { + elseif (($IsWindows) -or ((Test-Path Env:AGENT_OS) -and ($Env:AGENT_OS.StartsWith("Win")))) { Write-Host "On Windows build $Name using Clang" - $env:CC = "clang.exe" - $env:CXX = "clang++.exe" - $env:RC = "clang++.exe" + $CMAKE_C_COMPILER = "-DCMAKE_C_COMPILER=clang.exe" + $CMAKE_CXX_COMPILER = "-DCMAKE_CXX_COMPILER=clang++.exe" if ((!(Get-Command clang -ErrorAction SilentlyContinue) -and (choco find --idonly -l llvm) -contains "llvm") -or ` (Test-Path Env:/AGENT_OS)) { @@ -204,7 +65,8 @@ function Build-CMakeProject { # the Linux build catch tidy issues. $clangTidy = "-DCMAKE_CXX_CLANG_TIDY=clang-tidy" } - } else { + } + else { Write-Host "##vso[task.logissue type=warning;]Failed to identify the OS. Will use default CXX compiler" } @@ -218,15 +80,16 @@ function Build-CMakeProject { Push-Location $cmakeBuildFolder $buildType = $Env:BUILD_CONFIGURATION - if ($buildType -eq "Release"){ + if ($buildType -eq "Release") { $buildType = "RelWithDebInfo" } - cmake -G Ninja $clangTidy -D CMAKE_VERBOSE_MAKEFILE:BOOL=ON -D CMAKE_BUILD_TYPE="$buildType" ../.. | Write-Host + cmake -G Ninja $CMAKE_C_COMPILER $CMAKE_CXX_COMPILER $clangTidy -D CMAKE_BUILD_TYPE="$buildType" ../.. | Write-Host if ($LastExitCode -ne 0) { Write-Host "##vso[task.logissue type=error;]Failed to generate $Name." $all_ok = $false - } else { + } + else { cmake --build . --target install | Write-Host if ($LastExitCode -ne 0) { Write-Host "##vso[task.logissue type=error;]Failed to build $Name." @@ -236,13 +99,6 @@ function Build-CMakeProject { Pop-Location - $env:CXXFLAGS = $oldCXXFLAGS - $env:CFLAGS = $oldCFLAGS - - $env:CC = $oldCC - $env:CXX = $oldCXX - $env:RC = $oldRC - return $all_ok }