diff --git a/Simulation.sln b/Simulation.sln
index 8bf6718fb86..1a4a4abbd59 100644
--- a/Simulation.sln
+++ b/Simulation.sln
@@ -117,12 +117,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Controller", "Controller",
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QirController", "src\Qir\Controller\QirController.csproj", "{A77E6661-D143-4E3E-BCD1-8E321A966829}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests.QirController", "src\Qir\Controller\Tests.QirController\Tests.QirController.csproj", "{2E4B9604-A5CD-4B49-B1D4-A7AC8ABAEF68}"
-EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Execution", "Execution", "{442E66C8-F69F-44E9-9CD9-1F52C37EA41B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Quantum.Qir.Tools", "src\Qir\Execution\Tools\Microsoft.Quantum.Qir.Tools.csproj", "{C60226E3-98DE-4E92-AED4-B4A93D4CA063}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests.Microsoft.Quantum.Qir.Tools", "src\Qir\Execution\Tests.Microsoft.Quantum.Qir.Tools\Tests.Microsoft.Quantum.Qir.Tools.csproj", "{4794FC80-4594-403F-AFEC-4889EFE87EA0}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -775,22 +775,6 @@ Global
{A77E6661-D143-4E3E-BCD1-8E321A966829}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU
{A77E6661-D143-4E3E-BCD1-8E321A966829}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU
{A77E6661-D143-4E3E-BCD1-8E321A966829}.RelWithDebInfo|x64.Build.0 = Release|Any CPU
- {2E4B9604-A5CD-4B49-B1D4-A7AC8ABAEF68}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {2E4B9604-A5CD-4B49-B1D4-A7AC8ABAEF68}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {2E4B9604-A5CD-4B49-B1D4-A7AC8ABAEF68}.Debug|x64.ActiveCfg = Debug|Any CPU
- {2E4B9604-A5CD-4B49-B1D4-A7AC8ABAEF68}.Debug|x64.Build.0 = Debug|Any CPU
- {2E4B9604-A5CD-4B49-B1D4-A7AC8ABAEF68}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU
- {2E4B9604-A5CD-4B49-B1D4-A7AC8ABAEF68}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU
- {2E4B9604-A5CD-4B49-B1D4-A7AC8ABAEF68}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
- {2E4B9604-A5CD-4B49-B1D4-A7AC8ABAEF68}.MinSizeRel|x64.Build.0 = Debug|Any CPU
- {2E4B9604-A5CD-4B49-B1D4-A7AC8ABAEF68}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {2E4B9604-A5CD-4B49-B1D4-A7AC8ABAEF68}.Release|Any CPU.Build.0 = Release|Any CPU
- {2E4B9604-A5CD-4B49-B1D4-A7AC8ABAEF68}.Release|x64.ActiveCfg = Release|Any CPU
- {2E4B9604-A5CD-4B49-B1D4-A7AC8ABAEF68}.Release|x64.Build.0 = Release|Any CPU
- {2E4B9604-A5CD-4B49-B1D4-A7AC8ABAEF68}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU
- {2E4B9604-A5CD-4B49-B1D4-A7AC8ABAEF68}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU
- {2E4B9604-A5CD-4B49-B1D4-A7AC8ABAEF68}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU
- {2E4B9604-A5CD-4B49-B1D4-A7AC8ABAEF68}.RelWithDebInfo|x64.Build.0 = Release|Any CPU
{C60226E3-98DE-4E92-AED4-B4A93D4CA063}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C60226E3-98DE-4E92-AED4-B4A93D4CA063}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C60226E3-98DE-4E92-AED4-B4A93D4CA063}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -807,6 +791,22 @@ Global
{C60226E3-98DE-4E92-AED4-B4A93D4CA063}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU
{C60226E3-98DE-4E92-AED4-B4A93D4CA063}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU
{C60226E3-98DE-4E92-AED4-B4A93D4CA063}.RelWithDebInfo|x64.Build.0 = Release|Any CPU
+ {4794FC80-4594-403F-AFEC-4889EFE87EA0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {4794FC80-4594-403F-AFEC-4889EFE87EA0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {4794FC80-4594-403F-AFEC-4889EFE87EA0}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {4794FC80-4594-403F-AFEC-4889EFE87EA0}.Debug|x64.Build.0 = Debug|Any CPU
+ {4794FC80-4594-403F-AFEC-4889EFE87EA0}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU
+ {4794FC80-4594-403F-AFEC-4889EFE87EA0}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU
+ {4794FC80-4594-403F-AFEC-4889EFE87EA0}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
+ {4794FC80-4594-403F-AFEC-4889EFE87EA0}.MinSizeRel|x64.Build.0 = Debug|Any CPU
+ {4794FC80-4594-403F-AFEC-4889EFE87EA0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {4794FC80-4594-403F-AFEC-4889EFE87EA0}.Release|Any CPU.Build.0 = Release|Any CPU
+ {4794FC80-4594-403F-AFEC-4889EFE87EA0}.Release|x64.ActiveCfg = Release|Any CPU
+ {4794FC80-4594-403F-AFEC-4889EFE87EA0}.Release|x64.Build.0 = Release|Any CPU
+ {4794FC80-4594-403F-AFEC-4889EFE87EA0}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU
+ {4794FC80-4594-403F-AFEC-4889EFE87EA0}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU
+ {4794FC80-4594-403F-AFEC-4889EFE87EA0}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU
+ {4794FC80-4594-403F-AFEC-4889EFE87EA0}.RelWithDebInfo|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -862,9 +862,9 @@ Global
{D7D34736-A719-4B45-A33F-2723F59EC29D} = {A7DB7367-9FD6-4164-8263-A05077BE54AB}
{4E07F247-ED93-4497-8B58-022314308E67} = {F6C2D4C0-12DC-40E3-9C86-FA5308D9B567}
{A77E6661-D143-4E3E-BCD1-8E321A966829} = {4E07F247-ED93-4497-8B58-022314308E67}
- {2E4B9604-A5CD-4B49-B1D4-A7AC8ABAEF68} = {4E07F247-ED93-4497-8B58-022314308E67}
{442E66C8-F69F-44E9-9CD9-1F52C37EA41B} = {F6C2D4C0-12DC-40E3-9C86-FA5308D9B567}
{C60226E3-98DE-4E92-AED4-B4A93D4CA063} = {442E66C8-F69F-44E9-9CD9-1F52C37EA41B}
+ {4794FC80-4594-403F-AFEC-4889EFE87EA0} = {442E66C8-F69F-44E9-9CD9-1F52C37EA41B}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {929C0464-86D8-4F70-8835-0A5EAF930821}
diff --git a/src/Qir/Controller/Controller.cs b/src/Qir/Controller/Controller.cs
index 70378632128..09a8b1ef8c8 100644
--- a/src/Qir/Controller/Controller.cs
+++ b/src/Qir/Controller/Controller.cs
@@ -3,11 +3,11 @@
using System;
using System.IO;
+using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
-using Microsoft.Quantum.Qir.Driver;
-using Microsoft.Quantum.Qir.Executable;
using Microsoft.Quantum.Qir.Model;
+using Microsoft.Quantum.Qir.Tools.Executable;
using Microsoft.Quantum.Qir.Utility;
using QirExecutionWrapperSerialization = Microsoft.Quantum.QsCompiler.BondSchemas.QirExecutionWrapper.Protocols;
@@ -15,7 +15,6 @@ namespace Microsoft.Quantum.Qir
{
public static class Controller
{
- private const string SourceDirectoryPath = "src";
private const string BinaryDirectoryPath = "bin";
private const string ExecutableName = "simulation.exe";
@@ -25,9 +24,6 @@ public static async Task ExecuteAsync(
DirectoryInfo libraryDirectory,
DirectoryInfo includeDirectory,
FileInfo errorFile,
- IQirSourceFileGenerator driverGenerator,
- IQirExecutableGenerator executableGenerator,
- IQuantumExecutableRunner executableRunner,
ILogger logger)
{
try
@@ -37,20 +33,20 @@ public static async Task ExecuteAsync(
using var inputFileStream = inputFile.OpenRead();
var input = QirExecutionWrapperSerialization.DeserializeFromFastBinary(inputFileStream);
- // Step 2: Create driver.
- logger.LogInfo("Creating driver file.");
- var sourceDirectory = new DirectoryInfo(SourceDirectoryPath);
- await driverGenerator.GenerateQirSourceFilesAsync(sourceDirectory, input.EntryPoint, input.QirBytecode);
-
- // Step 3: Create executable.
- logger.LogInfo("Compiling and linking executable.");
- var binaryDirectory = new DirectoryInfo(BinaryDirectoryPath);
+ // Step 2: Create executable.
+ logger.LogInfo("Creating executable.");
+ var bytecodeArray = input.QirBytecode.Array.Skip(input.QirBytecode.Offset).Take(input.QirBytecode.Count).ToList().ToArray();
var executableFile = new FileInfo(Path.Combine(BinaryDirectoryPath, ExecutableName));
- await executableGenerator.GenerateExecutableAsync(executableFile, sourceDirectory, libraryDirectory, includeDirectory);
+ var executable = new QirFullStateExecutable(executableFile, bytecodeArray, logger);
+ await executable.BuildAsync(input.EntryPoint, libraryDirectory, includeDirectory);
- // Step 4: Run executable.
- logger.LogInfo("Running executable.");
- await executableRunner.RunExecutableAsync(executableFile, input.EntryPoint, outputFile);
+ // Step 3: Run executable.
+ if (outputFile.Exists)
+ {
+ outputFile.Delete();
+ }
+ using var outputStream = outputFile.OpenWrite();
+ await executable.RunAsync(input.EntryPoint, outputStream);
}
catch (Exception e)
{
diff --git a/src/Qir/Controller/Driver/IQirSourceFileGenerator.cs b/src/Qir/Controller/Driver/IQirSourceFileGenerator.cs
deleted file mode 100644
index 92e0449c77a..00000000000
--- a/src/Qir/Controller/Driver/IQirSourceFileGenerator.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License.
-
-using System;
-using System.IO;
-using System.Threading.Tasks;
-using Microsoft.Quantum.QsCompiler.BondSchemas.EntryPoint;
-
-namespace Microsoft.Quantum.Qir.Driver
-{
- public interface IQirSourceFileGenerator
- {
- ///
- /// Generates the C++ driver source file and writes the bytecode to a file.
- ///
- /// Directory to which driver and bytecode will be written.
- /// Entry point information.
- /// The QIR bytecode.
- ///
- Task GenerateQirSourceFilesAsync(DirectoryInfo sourceDirectory, EntryPointOperation entryPointOperation, ArraySegment bytecode);
- }
-}
diff --git a/src/Qir/Controller/Driver/QirSourceFileGenerator.cs b/src/Qir/Controller/Driver/QirSourceFileGenerator.cs
deleted file mode 100644
index 7a7cfe891a2..00000000000
--- a/src/Qir/Controller/Driver/QirSourceFileGenerator.cs
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License.
-
-using System;
-using System.IO;
-using System.Threading.Tasks;
-using Microsoft.Quantum.Qir.Utility;
-using Microsoft.Quantum.QsCompiler;
-using Microsoft.Quantum.QsCompiler.BondSchemas.EntryPoint;
-
-namespace Microsoft.Quantum.Qir.Driver
-{
- public class QirSourceFileGenerator : IQirSourceFileGenerator
- {
- private const string BytecodeFileName = "qir.bc";
- private const string DriverFileName = "driver.cpp";
- private readonly ILogger logger;
-
- public QirSourceFileGenerator(ILogger logger)
- {
- this.logger = logger;
- }
-
- public async Task GenerateQirSourceFilesAsync(DirectoryInfo sourceDirectory, EntryPointOperation entryPointOperation, ArraySegment bytecode)
- {
- if (sourceDirectory.Exists)
- {
- sourceDirectory.Delete(true);
- }
-
- sourceDirectory.Create();
- logger.LogInfo($"Created source directory at {sourceDirectory.FullName}.");
-
- // Create driver.
- var driverFile = new FileInfo(Path.Combine(sourceDirectory.FullName, DriverFileName));
- using var driverFileStream = driverFile.OpenWrite();
- GenerateQirDriverCppHelper(entryPointOperation, driverFileStream);
- logger.LogInfo($"Created driver file at {driverFile.FullName}.");
-
- // Create bytecode file.
- var bytecodeFile = new FileInfo(Path.Combine(sourceDirectory.FullName, BytecodeFileName));
- using var bytecodeFileStream = bytecodeFile.OpenWrite();
- await bytecodeFileStream.WriteAsync(bytecode.Array, bytecode.Offset, bytecode.Count);
- logger.LogInfo($"Created bytecode file at {bytecodeFile.FullName}.");
- }
-
- // Virtual method wrapper is to enable mocking in unit tests.
- public virtual void GenerateQirDriverCppHelper(EntryPointOperation entryPointOperation, Stream stream)
- {
- QirDriverGeneration.GenerateQirDriverCpp(entryPointOperation, stream);
- }
- }
-}
diff --git a/src/Qir/Controller/Executable/IQuantumExecutableRunner.cs b/src/Qir/Controller/Executable/IQuantumExecutableRunner.cs
deleted file mode 100644
index 135fbbbfb4f..00000000000
--- a/src/Qir/Controller/Executable/IQuantumExecutableRunner.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License.
-
-using System.IO;
-using System.Threading.Tasks;
-using Microsoft.Quantum.QsCompiler.BondSchemas.EntryPoint;
-
-namespace Microsoft.Quantum.Qir.Executable
-{
- public interface IQuantumExecutableRunner
- {
- ///
- /// Runs a quantum program executable with the given arguments.
- ///
- /// Location of the executable to run.
- /// Entry point and arguments to pass.
- /// Location to write program output.
- ///
- Task RunExecutableAsync(FileInfo executableFile, EntryPointOperation entryPointOperation, FileInfo outputFile);
- }
-}
diff --git a/src/Qir/Controller/Executable/QuantumExecutableRunner.cs b/src/Qir/Controller/Executable/QuantumExecutableRunner.cs
deleted file mode 100644
index 8ce2bcd41d7..00000000000
--- a/src/Qir/Controller/Executable/QuantumExecutableRunner.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License.
-
-using System.CommandLine.Invocation;
-using System.IO;
-using System.Threading.Tasks;
-using Microsoft.Quantum.Qir.Utility;
-using Microsoft.Quantum.QsCompiler;
-using Microsoft.Quantum.QsCompiler.BondSchemas.EntryPoint;
-
-namespace Microsoft.Quantum.Qir.Executable
-{
- public class QuantumExecutableRunner : IQuantumExecutableRunner
- {
- private readonly ILogger logger;
-
- public QuantumExecutableRunner(ILogger logger)
- {
- this.logger = logger;
- }
-
- public async Task RunExecutableAsync(FileInfo executableFile, EntryPointOperation entryPointOperation, FileInfo outputFile)
- {
- var arguments = QirDriverGeneration.GenerateCommandLineArguments(entryPointOperation.Arguments);
- logger.LogInfo($"Invoking executable {executableFile.FullName} with the following arguments: {arguments}");
- arguments = $"--simulation-output {outputFile.FullName} {arguments}";
- if (outputFile.Exists)
- {
- outputFile.Delete();
- }
-
- outputFile.Create().Dispose();
- var result = await Process.ExecuteAsync(
- executableFile.FullName,
- arguments,
- stdOut: s => { logger.LogInfo("executable: " + s); },
- stdErr: s => { logger.LogError("executable: " + s); });
- logger.LogInfo($"Executable has finished running. Result code: {result}");
- }
- }
-}
diff --git a/src/Qir/Controller/Program.cs b/src/Qir/Controller/Program.cs
index 6def5f9d223..df24e0632f9 100644
--- a/src/Qir/Controller/Program.cs
+++ b/src/Qir/Controller/Program.cs
@@ -4,8 +4,6 @@
using System.CommandLine;
using System.CommandLine.Invocation;
using System.IO;
-using Microsoft.Quantum.Qir.Driver;
-using Microsoft.Quantum.Qir.Executable;
using Microsoft.Quantum.Qir.Utility;
namespace Microsoft.Quantum.Qir
@@ -15,9 +13,6 @@ class Program
static void Main(string[] args)
{
var logger = new Logger(new Clock());
- var execGenerator = new QirExecutableGenerator(new ClangClient(logger), logger);
- var driverGenerator = new QirSourceFileGenerator(logger);
- var execRunner = new QuantumExecutableRunner(logger);
logger.LogInfo("QIR controller beginning.");
var rootCommand = new RootCommand(
@@ -69,7 +64,7 @@ static void Main(string[] args)
// Bind to a handler and invoke.
rootCommand.Handler = CommandHandler.Create(
async (input, output, libraryDirectory, includeDirectory, error) =>
- await Controller.ExecuteAsync(input, output, libraryDirectory, includeDirectory, error, driverGenerator, execGenerator, execRunner, logger));
+ await Controller.ExecuteAsync(input, output, libraryDirectory, includeDirectory, error, logger));
rootCommand.Invoke(args);
}
}
diff --git a/src/Qir/Controller/QirController.csproj b/src/Qir/Controller/QirController.csproj
index e9574233c00..c4398261366 100644
--- a/src/Qir/Controller/QirController.csproj
+++ b/src/Qir/Controller/QirController.csproj
@@ -26,6 +26,10 @@
+
+
+
+
True
diff --git a/src/Qir/Controller/Tests.QirController/ControllerTests.cs b/src/Qir/Controller/Tests.QirController/ControllerTests.cs
deleted file mode 100644
index 6e85b07976b..00000000000
--- a/src/Qir/Controller/Tests.QirController/ControllerTests.cs
+++ /dev/null
@@ -1,204 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License.
-
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Text.Json;
-using System.Threading.Tasks;
-using Microsoft.Quantum.Qir;
-using Microsoft.Quantum.Qir.Driver;
-using Microsoft.Quantum.Qir.Executable;
-using Microsoft.Quantum.Qir.Model;
-using Microsoft.Quantum.Qir.Utility;
-using Microsoft.Quantum.QsCompiler.BondSchemas.EntryPoint;
-using Microsoft.Quantum.QsCompiler.BondSchemas.QirExecutionWrapper;
-using Moq;
-using Xunit;
-using QirExecutionWrapperSerialization = Microsoft.Quantum.QsCompiler.BondSchemas.QirExecutionWrapper.Protocols;
-
-namespace Tests.QirController
-{
- public class ControllerTests : IDisposable
- {
- private Mock driverGeneratorMock;
- private Mock executableGeneratorMock;
- private Mock executableRunnerMock;
- private Mock loggerMock;
- private FileInfo inputFile;
- private FileInfo bytecodeFile;
- private FileInfo errorFile;
- private FileInfo outputFile;
- private QirExecutionWrapper input;
-
- public ControllerTests()
- {
- driverGeneratorMock = new Mock();
- executableGeneratorMock = new Mock();
- executableRunnerMock = new Mock();
- inputFile = new FileInfo($"{Guid.NewGuid()}-input");
- bytecodeFile = new FileInfo($"{Guid.NewGuid()}-bytecode");
- errorFile = new FileInfo($"{Guid.NewGuid()}-error");
- outputFile = new FileInfo($"{Guid.NewGuid()}-output");
- loggerMock = new Mock();
-
- // Create a QirExecutableWrapper to be used by the tests.
- byte[] bytecode = { 1, 2, 3, 4, 5 };
- input = new QirExecutionWrapper()
- {
- EntryPoint = new EntryPointOperation()
- {
- Arguments = new List
- {
- new Argument()
- {
- Position = 0,
- Name = "argname",
- Values = new List { new ArgumentValue { String = "argvalue" } },
- }
- }
- },
- QirBytecode = new ArraySegment(bytecode, 1, 3),
- };
- using var fileStream = inputFile.OpenWrite();
- QirExecutionWrapperSerialization.SerializeToFastBinary(input, fileStream);
- }
-
- public void Dispose()
- {
- inputFile.Delete();
- bytecodeFile.Delete();
- errorFile.Delete();
- outputFile.Delete();
- }
-
- [Fact]
- public async Task TestExecute()
- {
- var libraryDirectory = new DirectoryInfo("libraries");
- var includeDirectory = new DirectoryInfo("includes");
- FileInfo actualExecutableFile = null;
- Action generateExecutableCallback = async (executableFile, srcDir, libDir, inclDir) =>
- {
- actualExecutableFile = executableFile;
- await Task.CompletedTask;
- };
- executableGeneratorMock.Setup(obj => obj.GenerateExecutableAsync(
- It.IsAny(),
- It.IsAny(),
- It.Is(actualLibraryDirectory => actualLibraryDirectory.FullName == libraryDirectory.FullName),
- It.Is(actualIncludeDirectory => actualIncludeDirectory.FullName == includeDirectory.FullName))).Callback(generateExecutableCallback);
-
- await Controller.ExecuteAsync(
- inputFile,
- outputFile,
- libraryDirectory,
- includeDirectory,
- errorFile,
- driverGeneratorMock.Object,
- executableGeneratorMock.Object,
- executableRunnerMock.Object,
- loggerMock.Object);
-
- // Verify driver was created.
- driverGeneratorMock.Verify(obj => obj.GenerateQirSourceFilesAsync(
- It.IsAny(),
- It.Is(entryPoint => Util.EntryPointsAreEqual(entryPoint, input.EntryPoint)),
- It.Is>(bytecode => BytecodesAreEqual(bytecode, input.QirBytecode))));
-
- // Verify executable was generated.
- executableGeneratorMock.Verify(obj => obj.GenerateExecutableAsync(
- It.IsAny(),
- It.IsAny(),
- It.Is(actualLibraryDirectory => actualLibraryDirectory.FullName == libraryDirectory.FullName),
- It.Is(actualIncludeDirectory => actualIncludeDirectory.FullName == includeDirectory.FullName)));
- Assert.NotNull(actualExecutableFile);
-
- // Verify executable was run.
- executableRunnerMock.Verify(obj => obj.RunExecutableAsync(
- It.Is(executableFile => actualExecutableFile.FullName == executableFile.FullName),
- It.Is(entryPoint => Util.EntryPointsAreEqual(entryPoint, input.EntryPoint)),
- It.Is(actualOutputFile => actualOutputFile.FullName == outputFile.FullName)));
- }
-
- [Fact]
- public async Task TestExecuteEncountersGenericException()
- {
- var libraryDirectory = new DirectoryInfo("libraries");
- var includeDirectory = new DirectoryInfo("includes");
- executableGeneratorMock.Setup(obj => obj.GenerateExecutableAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()))
- .ThrowsAsync(new Exception("exception message"));
-
- // Execute controller.
- await Controller.ExecuteAsync(
- inputFile,
- outputFile,
- libraryDirectory,
- includeDirectory,
- errorFile,
- driverGeneratorMock.Object,
- executableGeneratorMock.Object,
- executableRunnerMock.Object,
- loggerMock.Object);
-
- // Verify error file was created and contains the error.
- Assert.True(errorFile.Exists);
- using var errorFileStream = errorFile.OpenRead();
- using var streamReader = new StreamReader(errorFileStream);
- var errorFileContents = await streamReader.ReadToEndAsync();
- var error = JsonSerializer.Deserialize(errorFileContents);
- Assert.Equal(ErrorMessages.InternalError, error.Message);
- Assert.Equal(Constant.ErrorCode.InternalError, error.Code);
- }
-
- [Fact]
- public async Task TestExecuteEncountersControllerException()
- {
- var exceptionMessage = "exception message";
- var errorCode = "error code";
- var libraryDirectory = new DirectoryInfo("libraries");
- var includeDirectory = new DirectoryInfo("includes");
- executableGeneratorMock.Setup(obj => obj.GenerateExecutableAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()))
- .ThrowsAsync(new ControllerException(exceptionMessage, errorCode));
-
- // Execute controller.
- await Controller.ExecuteAsync(
- inputFile,
- outputFile,
- libraryDirectory,
- includeDirectory,
- errorFile,
- driverGeneratorMock.Object,
- executableGeneratorMock.Object,
- executableRunnerMock.Object,
- loggerMock.Object);
-
- // Verify error file was created and contains the error.
- Assert.True(errorFile.Exists);
- using var errorFileStream = errorFile.OpenRead();
- using var streamReader = new StreamReader(errorFileStream);
- var errorFileContents = await streamReader.ReadToEndAsync();
- var error = JsonSerializer.Deserialize(errorFileContents);
- Assert.Equal(exceptionMessage, error.Message);
- Assert.Equal(errorCode, error.Code);
- }
-
- private bool BytecodesAreEqual(ArraySegment bytecodeA, ArraySegment bytecodeB)
- {
- if (bytecodeA.Count != bytecodeB.Count)
- {
- return false;
- }
-
- for (var i = 0; i < bytecodeA.Count; ++i)
- {
- if (bytecodeA[i] != bytecodeB[i])
- {
- return false;
- }
- }
-
- return true;
- }
- }
-}
diff --git a/src/Qir/Controller/Tests.QirController/QirDriverGeneratorTests.cs b/src/Qir/Controller/Tests.QirController/QirDriverGeneratorTests.cs
deleted file mode 100644
index e93837e62ea..00000000000
--- a/src/Qir/Controller/Tests.QirController/QirDriverGeneratorTests.cs
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License.
-
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Threading.Tasks;
-using Microsoft.Quantum.Qir.Driver;
-using Microsoft.Quantum.Qir.Utility;
-using Microsoft.Quantum.QsCompiler.BondSchemas.EntryPoint;
-using Moq;
-using Xunit;
-
-namespace Tests.QirController
-{
- public class QirDriverGeneratorTests : IDisposable
- {
- private readonly Mock driverGeneratorMock;
- private readonly DirectoryInfo sourceDirectory;
-
- public QirDriverGeneratorTests()
- {
- driverGeneratorMock = new Mock(Mock.Of()) { CallBase = true };
- driverGeneratorMock.Setup(obj => obj.GenerateQirDriverCppHelper(It.IsAny(), It.IsAny()));
- sourceDirectory = new DirectoryInfo($"{Guid.NewGuid()}-source");
- }
-
- public void Dispose()
- {
- Util.DeleteDirectory(sourceDirectory);
- }
-
- [Fact]
- public async Task TestGenerateDriver()
- {
- var entryPoint = new EntryPointOperation()
- {
- Arguments = new List
- {
- new Argument()
- {
- Position = 0,
- Name = "argname",
- Values = new List { new ArgumentValue { String = "argvalue" } },
- }
- }
- };
- byte[] bytes = { 1, 2, 3, 4, 5 };
- var bytecode = new ArraySegment(bytes, 1, 3);
- await driverGeneratorMock.Object.GenerateQirSourceFilesAsync(sourceDirectory, entryPoint, bytecode);
- driverGeneratorMock.Verify(obj => obj.GenerateQirDriverCppHelper(It.Is(actualEntryPoint => Util.EntryPointsAreEqual(entryPoint, actualEntryPoint)), It.IsAny()));
-
- // Verify that the "bytecode" file was created correctly.
- var bytecodeFilePath = new FileInfo(Path.Combine(sourceDirectory.FullName, "qir.bc"));
- using var bytecodeFileStream = bytecodeFilePath.OpenRead();
- Assert.Equal(bytecodeFileStream.Length, bytecode.Count);
- for (var i = 0; i < bytecodeFileStream.Length; ++i)
- {
- Assert.Equal(bytecode[i], bytecodeFileStream.ReadByte());
- }
- }
- }
-}
diff --git a/src/Qir/Controller/test-cases/standalone-input-test.in b/src/Qir/Controller/test-cases/standalone-input-test.in
index 2251eb15f36..82a74f144f9 100644
Binary files a/src/Qir/Controller/test-cases/standalone-input-test.in and b/src/Qir/Controller/test-cases/standalone-input-test.in differ
diff --git a/src/Qir/Controller/Tests.QirController/LoggerTests.cs b/src/Qir/Execution/Tests.Microsoft.Quantum.Qir.Tools/LoggerTests.cs
similarity index 98%
rename from src/Qir/Controller/Tests.QirController/LoggerTests.cs
rename to src/Qir/Execution/Tests.Microsoft.Quantum.Qir.Tools/LoggerTests.cs
index ee7adfee70a..1df4bf96552 100644
--- a/src/Qir/Controller/Tests.QirController/LoggerTests.cs
+++ b/src/Qir/Execution/Tests.Microsoft.Quantum.Qir.Tools/LoggerTests.cs
@@ -7,7 +7,7 @@
using Moq;
using Xunit;
-namespace Tests.QirController
+namespace Tests.Microsoft.Quantum.Qir.Tools
{
public class LoggerTests
{
diff --git a/src/Qir/Controller/Tests.QirController/QirExecutableGeneratorTests.cs b/src/Qir/Execution/Tests.Microsoft.Quantum.Qir.Tools/QirExecutableGeneratorTests.cs
similarity index 92%
rename from src/Qir/Controller/Tests.QirController/QirExecutableGeneratorTests.cs
rename to src/Qir/Execution/Tests.Microsoft.Quantum.Qir.Tools/QirExecutableGeneratorTests.cs
index 3d9da400687..93a6f98a786 100644
--- a/src/Qir/Controller/Tests.QirController/QirExecutableGeneratorTests.cs
+++ b/src/Qir/Execution/Tests.Microsoft.Quantum.Qir.Tools/QirExecutableGeneratorTests.cs
@@ -6,12 +6,12 @@
using System.IO;
using System.Linq;
using System.Threading.Tasks;
-using Microsoft.Quantum.Qir.Executable;
+using Microsoft.Quantum.Qir.Tools.Executable;
using Microsoft.Quantum.Qir.Utility;
using Moq;
using Xunit;
-namespace Tests.QirController
+namespace Tests.Microsoft.Quantum.Qir.Tools
{
public class QirExecutableGeneratorTests : IDisposable
{
@@ -23,6 +23,7 @@ public class QirExecutableGeneratorTests : IDisposable
private readonly DirectoryInfo binDirectory;
private readonly IList libraryFiles;
private readonly IList sourceFiles;
+ private IList linkLibraries;
public QirExecutableGeneratorTests()
{
@@ -49,6 +50,7 @@ public QirExecutableGeneratorTests()
CreateFile("src1.cpp", sourceDirectory, "src1 contents"),
CreateFile("src2.bc", sourceDirectory, "src2 contents"),
};
+ linkLibraries = new List { "lib1", "lib2" };
}
public void Dispose()
@@ -62,19 +64,13 @@ public void Dispose()
[Fact]
public async Task TestGenerateExecutable()
{
- string[] expectedLibraries = {
- "Microsoft.Quantum.Qir.Runtime",
- "Microsoft.Quantum.Qir.QSharp.Foundation",
- "Microsoft.Quantum.Qir.QSharp.Core"
- };
-
var executableFile = new FileInfo(Path.Combine(binDirectory.FullName, "executableFile"));
- await executableGenerator.GenerateExecutableAsync(executableFile, sourceDirectory, libraryDirectory, includeDirectory);
+ await executableGenerator.GenerateExecutableAsync(executableFile, sourceDirectory, libraryDirectory, includeDirectory, linkLibraries);
// Verify invocation of clang.
clangClientMock.Verify(obj => obj.CreateExecutableAsync(
It.Is(s => s.SequenceEqual(sourceFiles.Select(fileInfo => fileInfo.FullName))),
- It.Is(s => s.SequenceEqual(expectedLibraries)),
+ It.Is(s => s.SequenceEqual(linkLibraries)),
libraryDirectory.FullName,
includeDirectory.FullName,
executableFile.FullName));
diff --git a/src/Qir/Execution/Tests.Microsoft.Quantum.Qir.Tools/QirExecutableTests.cs b/src/Qir/Execution/Tests.Microsoft.Quantum.Qir.Tools/QirExecutableTests.cs
new file mode 100644
index 00000000000..217a12ca09c
--- /dev/null
+++ b/src/Qir/Execution/Tests.Microsoft.Quantum.Qir.Tools/QirExecutableTests.cs
@@ -0,0 +1,112 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Threading.Tasks;
+using Microsoft.Quantum.Qir.Tools.Driver;
+using Microsoft.Quantum.Qir.Tools.Executable;
+using Microsoft.Quantum.Qir.Utility;
+using Microsoft.Quantum.QsCompiler.BondSchemas.EntryPoint;
+using Moq;
+using Xunit;
+
+namespace Tests.Microsoft.Quantum.Qir.Tools
+{
+ public class QirExecutableTests : IDisposable
+ {
+ private readonly DirectoryInfo sourceDirectory;
+ private readonly DirectoryInfo includeDirectory;
+ private readonly DirectoryInfo libraryDirectory;
+ private readonly DirectoryInfo binDirectory;
+ private readonly Mock driverGeneratorMock;
+ private readonly Mock executableGeneratorMock;
+ private readonly Mock runnerMock;
+ private readonly Mock qirExecutable;
+ private readonly FileInfo executableFile;
+ private readonly byte[] qirBytecode = { 1, 2, 3, 4, 5 };
+ private readonly IList linkLibraries;
+
+ public QirExecutableTests()
+ {
+ // Set up files.
+ var prefix = Guid.NewGuid().ToString();
+ binDirectory = new DirectoryInfo($"{prefix}-bin");
+ binDirectory.Create();
+ libraryDirectory = new DirectoryInfo($"{prefix}-library");
+ libraryDirectory.Create();
+ includeDirectory = new DirectoryInfo($"{prefix}-include");
+ includeDirectory.Create();
+ sourceDirectory = new DirectoryInfo($"{prefix}-source");
+ sourceDirectory.Create();
+ executableFile = new FileInfo(Path.Combine(binDirectory.FullName, "executable"));
+ driverGeneratorMock = new Mock();
+ executableGeneratorMock = new Mock();
+ runnerMock = new Mock();
+ qirExecutable = new Mock(executableFile, qirBytecode, Mock.Of(), driverGeneratorMock.Object, executableGeneratorMock.Object, runnerMock.Object) { CallBase = true };
+ linkLibraries = new List { "lib1", "lib2" };
+ qirExecutable.SetupGet(obj => obj.LinkLibraries).Returns(linkLibraries);
+ qirExecutable.SetupGet(obj => obj.SourceDirectoryPath).Returns(sourceDirectory.FullName);
+ qirExecutable.SetupGet(obj => obj.DriverFileExtension).Returns(".cpp");
+ }
+
+ public void Dispose()
+ {
+ Util.DeleteDirectory(sourceDirectory);
+ Util.DeleteDirectory(includeDirectory);
+ Util.DeleteDirectory(libraryDirectory);
+ Util.DeleteDirectory(binDirectory);
+ }
+
+ [Fact]
+ public async Task TestBuild()
+ {
+ // Set up.
+ var entryPoint = new EntryPointOperation();
+ var driverFileContents = "driver file contents";
+ driverGeneratorMock.Setup(obj => obj.GenerateAsync(entryPoint, It.IsAny())).Callback((entryPoint, stream) =>
+ {
+ using var streamWriter = new StreamWriter(stream);
+ streamWriter.Write(driverFileContents);
+ });
+
+ // Build the executable.
+ await qirExecutable.Object.BuildAsync(entryPoint, libraryDirectory, includeDirectory);
+
+ // Verify that the "bytecode" file was created correctly.
+ var bytecodeFilePath = new FileInfo(Path.Combine(sourceDirectory.FullName, "qir.bc"));
+ using var bytecodeFileStream = bytecodeFilePath.OpenRead();
+ Assert.Equal(bytecodeFileStream.Length, qirBytecode.Length);
+ for (var i = 0; i < bytecodeFileStream.Length; ++i)
+ {
+ Assert.Equal(qirBytecode[i], bytecodeFileStream.ReadByte());
+ }
+
+ // Verify that the driver was written to the correct file.
+ var driver = new FileInfo(Path.Combine(sourceDirectory.FullName, "driver.cpp"));
+ using var driverStreamReader = driver.OpenText();
+ var actualDriverContents = driverStreamReader.ReadToEnd();
+ Assert.Equal(driverFileContents, actualDriverContents);
+
+ // Verify that the executable was generated.
+ executableGeneratorMock.Verify(obj => obj.GenerateExecutableAsync(executableFile, It.Is(arg => arg.FullName == sourceDirectory.FullName), libraryDirectory, includeDirectory, linkLibraries));
+ }
+
+ [Fact]
+ public async Task TestRun()
+ {
+ // Set up.
+ using var outputStream = new MemoryStream();
+ var entryPoint = new EntryPointOperation();
+ var arguments = "arguments";
+ driverGeneratorMock.Setup(obj => obj.GetCommandLineArguments(entryPoint)).Returns(arguments);
+
+ // Run executable.
+ await qirExecutable.Object.RunAsync(entryPoint, outputStream);
+
+ // Verify runner was invoked properly.
+ runnerMock.Verify(obj => obj.RunExecutableAsync(executableFile, outputStream, arguments));
+ }
+ }
+}
diff --git a/src/Qir/Controller/Tests.QirController/Tests.QirController.csproj b/src/Qir/Execution/Tests.Microsoft.Quantum.Qir.Tools/Tests.Microsoft.Quantum.Qir.Tools.csproj
similarity index 87%
rename from src/Qir/Controller/Tests.QirController/Tests.QirController.csproj
rename to src/Qir/Execution/Tests.Microsoft.Quantum.Qir.Tools/Tests.Microsoft.Quantum.Qir.Tools.csproj
index ba5183ca742..55ffaa29bd4 100644
--- a/src/Qir/Controller/Tests.QirController/Tests.QirController.csproj
+++ b/src/Qir/Execution/Tests.Microsoft.Quantum.Qir.Tools/Tests.Microsoft.Quantum.Qir.Tools.csproj
@@ -14,7 +14,7 @@
-
+
diff --git a/src/Qir/Controller/Tests.QirController/Util.cs b/src/Qir/Execution/Tests.Microsoft.Quantum.Qir.Tools/Util.cs
similarity index 95%
rename from src/Qir/Controller/Tests.QirController/Util.cs
rename to src/Qir/Execution/Tests.Microsoft.Quantum.Qir.Tools/Util.cs
index 476848705ea..85c1d3a90e6 100644
--- a/src/Qir/Controller/Tests.QirController/Util.cs
+++ b/src/Qir/Execution/Tests.Microsoft.Quantum.Qir.Tools/Util.cs
@@ -5,7 +5,7 @@
using System.Reflection;
using Microsoft.Quantum.QsCompiler.BondSchemas.EntryPoint;
-namespace Tests.QirController
+namespace Tests.Microsoft.Quantum.Qir.Tools
{
public static class Util
{
diff --git a/src/Qir/Execution/Tools/AssemblyInfo.cs b/src/Qir/Execution/Tools/AssemblyInfo.cs
new file mode 100644
index 00000000000..1a412a83263
--- /dev/null
+++ b/src/Qir/Execution/Tools/AssemblyInfo.cs
@@ -0,0 +1,23 @@
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// In SDK-style projects such as this one, several assembly attributes that were historically
+// defined in this file are now automatically added during build and populated with
+// values defined in project properties. For details of which attributes are included
+// and how to customise this process see: https://aka.ms/assembly-info-properties
+
+
+// Setting ComVisible to false makes the types in this assembly not visible to COM
+// components. If you need to access a type in this assembly from COM, set the ComVisible
+// attribute to true on that type.
+
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM.
+
+[assembly: Guid("1594aae8-0e24-442b-9201-430ce9ee4d2e")]
+
+[assembly: InternalsVisibleTo("Tests.Microsoft.Quantum.Qir.Tools")]
+
+// This is required to mock internals in tests.
+[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
diff --git a/src/Qir/Execution/Tools/Driver/IQirDriverGenerator.cs b/src/Qir/Execution/Tools/Driver/IQirDriverGenerator.cs
new file mode 100644
index 00000000000..5c995bd7d0a
--- /dev/null
+++ b/src/Qir/Execution/Tools/Driver/IQirDriverGenerator.cs
@@ -0,0 +1,16 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.IO;
+using System.Threading.Tasks;
+using Microsoft.Quantum.QsCompiler.BondSchemas.EntryPoint;
+
+namespace Microsoft.Quantum.Qir.Tools.Driver
+{
+ public interface IQirDriverGenerator
+ {
+ Task GenerateAsync(EntryPointOperation entryPoint, Stream stream);
+
+ string GetCommandLineArguments(EntryPointOperation entryPoint);
+ }
+}
diff --git a/src/Qir/Execution/Tools/Driver/QirFullStateDriverGenerator.cs b/src/Qir/Execution/Tools/Driver/QirFullStateDriverGenerator.cs
new file mode 100644
index 00000000000..e09ac1196c1
--- /dev/null
+++ b/src/Qir/Execution/Tools/Driver/QirFullStateDriverGenerator.cs
@@ -0,0 +1,23 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.IO;
+using System.Threading.Tasks;
+using Microsoft.Quantum.QsCompiler;
+using Microsoft.Quantum.QsCompiler.BondSchemas.EntryPoint;
+
+namespace Microsoft.Quantum.Qir.Tools.Driver
+{
+ public class QirFullStateDriverGenerator: IQirDriverGenerator
+ {
+ public async Task GenerateAsync(EntryPointOperation entryPoint, Stream stream)
+ {
+ await Task.Run(() => QirDriverGeneration.GenerateQirDriverCpp(entryPoint, stream));
+ }
+
+ public string GetCommandLineArguments(EntryPointOperation entryPoint)
+ {
+ return QirDriverGeneration.GenerateCommandLineArguments(entryPoint.Arguments);
+ }
+ }
+}
diff --git a/src/Qir/Controller/Executable/ClangClient.cs b/src/Qir/Execution/Tools/Executable/ClangClient.cs
similarity index 54%
rename from src/Qir/Controller/Executable/ClangClient.cs
rename to src/Qir/Execution/Tools/Executable/ClangClient.cs
index 81bd435aff4..d4a204642a2 100644
--- a/src/Qir/Controller/Executable/ClangClient.cs
+++ b/src/Qir/Execution/Tools/Executable/ClangClient.cs
@@ -1,13 +1,13 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
-using System.CommandLine.Invocation;
+using System.Diagnostics;
using System.Threading.Tasks;
using Microsoft.Quantum.Qir.Utility;
-namespace Microsoft.Quantum.Qir.Executable
+namespace Microsoft.Quantum.Qir.Tools.Executable
{
- public class ClangClient : IClangClient
+ internal class ClangClient : IClangClient
{
private const string LinkFlag = " -l ";
private readonly ILogger logger;
@@ -23,13 +23,19 @@ public async Task CreateExecutableAsync(string[] inputFiles, string[] libraries,
// string.Join does not automatically prepend the delimiter, so it is included again in the string here.
var librariesArg = $"{LinkFlag} {string.Join(LinkFlag, libraries)}";
- var arguments = $"-v {inputsArg} -I {includePath} -L {libraryPath} {librariesArg} -o {outputPath}";
+ var arguments = $"{inputsArg} -I {includePath} -L {libraryPath} {librariesArg} -o {outputPath}";
logger.LogInfo($"Invoking clang with the following arguments: {arguments}");
- var result = await Process.ExecuteAsync(
- "clang",
- arguments,
- stdOut: s => { logger.LogInfo("clang: " + s); },
- stdErr: s => { logger.LogError("clang: " + s); });
+ var taskCompletionSource = new TaskCompletionSource();
+ using var process = new Process();
+ process.StartInfo = new ProcessStartInfo
+ {
+ FileName = "clang",
+ Arguments = arguments,
+ };
+ process.EnableRaisingEvents = true;
+ process.Exited += (sender, args) => { taskCompletionSource.SetResult(true); };
+ process.Start();
+ await taskCompletionSource.Task;
}
}
}
diff --git a/src/Qir/Controller/Executable/IClangClient.cs b/src/Qir/Execution/Tools/Executable/IClangClient.cs
similarity index 80%
rename from src/Qir/Controller/Executable/IClangClient.cs
rename to src/Qir/Execution/Tools/Executable/IClangClient.cs
index 7e7a8e1c95d..f5a1bb38135 100644
--- a/src/Qir/Controller/Executable/IClangClient.cs
+++ b/src/Qir/Execution/Tools/Executable/IClangClient.cs
@@ -3,12 +3,12 @@
using System.Threading.Tasks;
-namespace Microsoft.Quantum.Qir.Executable
+namespace Microsoft.Quantum.Qir.Tools.Executable
{
///
/// Wraps the 'clang' tool used for compilation.
///
- public interface IClangClient
+ internal interface IClangClient
{
Task CreateExecutableAsync(string[] inputFiles, string[] libraries, string libraryPath, string includePath, string outputPath);
}
diff --git a/src/Qir/Execution/Tools/Executable/IQirExecutable.cs b/src/Qir/Execution/Tools/Executable/IQirExecutable.cs
new file mode 100644
index 00000000000..6dc5914b5ea
--- /dev/null
+++ b/src/Qir/Execution/Tools/Executable/IQirExecutable.cs
@@ -0,0 +1,29 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.IO;
+using System.Threading.Tasks;
+using Microsoft.Quantum.QsCompiler.BondSchemas.EntryPoint;
+
+namespace Microsoft.Quantum.Qir.Tools.Executable
+{
+ public interface IQirExecutable
+ {
+ ///
+ /// Builds the executable.
+ ///
+ /// Entry point operation.
+ /// Directory containing libraries to link.
+ /// Directory containing files to include.
+ ///
+ Task BuildAsync(EntryPointOperation entryPoint, DirectoryInfo libraryDirectory, DirectoryInfo includeDirectory);
+
+ ///
+ /// Runs the executable.
+ ///
+ /// Entry point operation.
+ /// Stream to which output will be written.
+ ///
+ Task RunAsync(EntryPointOperation entryPoint, Stream output);
+ }
+}
diff --git a/src/Qir/Controller/Executable/IQirExecutableGenerator.cs b/src/Qir/Execution/Tools/Executable/IQirExecutableGenerator.cs
similarity index 75%
rename from src/Qir/Controller/Executable/IQirExecutableGenerator.cs
rename to src/Qir/Execution/Tools/Executable/IQirExecutableGenerator.cs
index e8ce44f7b7a..3ddb310f98e 100644
--- a/src/Qir/Controller/Executable/IQirExecutableGenerator.cs
+++ b/src/Qir/Execution/Tools/Executable/IQirExecutableGenerator.cs
@@ -1,12 +1,13 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
+using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
-namespace Microsoft.Quantum.Qir.Executable
+namespace Microsoft.Quantum.Qir.Tools.Executable
{
- public interface IQirExecutableGenerator
+ internal interface IQirExecutableGenerator
{
///
/// Generates a quantum simulation program executable.
@@ -15,7 +16,8 @@ public interface IQirExecutableGenerator
/// Location of the source files.
/// Location of the libraries that must be linked.
/// Location of the headers that must be included.
+ /// Libraries to link.
///
- public Task GenerateExecutableAsync(FileInfo executableFile, DirectoryInfo sourceDirectory, DirectoryInfo libraryDirectory, DirectoryInfo includeDirectory);
+ public Task GenerateExecutableAsync(FileInfo executableFile, DirectoryInfo sourceDirectory, DirectoryInfo libraryDirectory, DirectoryInfo includeDirectory, IList linkLibraries);
}
}
diff --git a/src/Qir/Execution/Tools/Executable/IQuantumExecutableRunner.cs b/src/Qir/Execution/Tools/Executable/IQuantumExecutableRunner.cs
new file mode 100644
index 00000000000..292cb394737
--- /dev/null
+++ b/src/Qir/Execution/Tools/Executable/IQuantumExecutableRunner.cs
@@ -0,0 +1,20 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.IO;
+using System.Threading.Tasks;
+
+namespace Microsoft.Quantum.Qir.Tools.Executable
+{
+ internal interface IQuantumExecutableRunner
+ {
+ ///
+ /// Runs a quantum program executable with the given arguments.
+ ///
+ /// Location of the executable to run.
+ /// Stream to write program output.
+ /// Arguments to supply the program with.
+ ///
+ Task RunExecutableAsync(FileInfo executableFile, Stream stream, string arguments);
+ }
+}
diff --git a/src/Qir/Execution/Tools/Executable/QirExecutable.cs b/src/Qir/Execution/Tools/Executable/QirExecutable.cs
new file mode 100644
index 00000000000..265006d2034
--- /dev/null
+++ b/src/Qir/Execution/Tools/Executable/QirExecutable.cs
@@ -0,0 +1,91 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Collections.Generic;
+using System.IO;
+using System.Threading.Tasks;
+using Microsoft.Quantum.Qir.Tools.Driver;
+using Microsoft.Quantum.Qir.Utility;
+using Microsoft.Quantum.QsCompiler.BondSchemas.EntryPoint;
+
+namespace Microsoft.Quantum.Qir.Tools.Executable
+{
+ ///
+ /// Base for creating and running QIR-based executables.
+ ///
+ public abstract class QirExecutable : IQirExecutable
+ {
+ private const string DriverFileName = "driver";
+ private const string BytecodeFileName = "qir.bc";
+
+ public virtual string SourceDirectoryPath => "src";
+ public abstract string DriverFileExtension { get; }
+
+ protected FileInfo ExecutableFile { get; }
+
+ private readonly byte[] qirBytecode;
+ private readonly ILogger logger;
+ private readonly IQuantumExecutableRunner runner;
+ private readonly IQirDriverGenerator driverGenerator;
+ private readonly IQirExecutableGenerator executableGenerator;
+
+ public QirExecutable(FileInfo executableFile, byte[] qirBytecode, IQirDriverGenerator driverGenerator, ILogger logger = null)
+ : this(executableFile,
+ qirBytecode,
+ logger ?? new Logger(new Clock()),
+ driverGenerator,
+ new QirExecutableGenerator(new ClangClient(logger), logger),
+ new QuantumExecutableRunner(logger))
+ {
+ }
+
+ internal QirExecutable(FileInfo executableFile, byte[] qirBytecode, ILogger logger, IQirDriverGenerator driverGenerator, IQirExecutableGenerator executableGenerator, IQuantumExecutableRunner runner)
+ {
+ ExecutableFile = executableFile;
+ this.qirBytecode = qirBytecode;
+ this.logger = logger;
+ this.runner = runner;
+ this.driverGenerator = driverGenerator;
+ this.executableGenerator = executableGenerator;
+ }
+
+ public async Task BuildAsync(EntryPointOperation entryPoint, DirectoryInfo libraryDirectory, DirectoryInfo includeDirectory)
+ {
+ var sourceDirectory = new DirectoryInfo(SourceDirectoryPath);
+ if (sourceDirectory.Exists)
+ {
+ sourceDirectory.Delete(true);
+ }
+
+ sourceDirectory.Create();
+ logger.LogInfo($"Created source directory at {sourceDirectory.FullName}.");
+
+ // Create driver.
+ var driverFileNameWithExtension = Path.ChangeExtension(DriverFileName, DriverFileExtension);
+ var driverFile = new FileInfo(Path.Combine(sourceDirectory.FullName, driverFileNameWithExtension));
+ using (var driverFileStream = driverFile.OpenWrite())
+ {
+ await driverGenerator.GenerateAsync(entryPoint, driverFileStream);
+ }
+ logger.LogInfo($"Created driver file at {driverFile.FullName}.");
+
+ // Create bytecode file.
+ var bytecodeFile = new FileInfo(Path.Combine(sourceDirectory.FullName, BytecodeFileName));
+ using (var bytecodeFileStream = bytecodeFile.OpenWrite())
+ {
+ await bytecodeFileStream.WriteAsync(qirBytecode);
+ }
+ logger.LogInfo($"Created bytecode file at {bytecodeFile.FullName}.");
+
+ await executableGenerator.GenerateExecutableAsync(ExecutableFile, sourceDirectory, libraryDirectory, includeDirectory, LinkLibraries);
+ }
+
+ public async Task RunAsync(EntryPointOperation entryPoint, Stream output)
+ {
+ var stringArguments = driverGenerator.GetCommandLineArguments(entryPoint);
+ await runner.RunExecutableAsync(ExecutableFile, output, stringArguments);
+ }
+
+ public abstract IList LinkLibraries { get; }
+ }
+}
diff --git a/src/Qir/Controller/Executable/QirExecutableGenerator.cs b/src/Qir/Execution/Tools/Executable/QirExecutableGenerator.cs
similarity index 80%
rename from src/Qir/Controller/Executable/QirExecutableGenerator.cs
rename to src/Qir/Execution/Tools/Executable/QirExecutableGenerator.cs
index 9445f300115..80eaf8a768a 100644
--- a/src/Qir/Controller/Executable/QirExecutableGenerator.cs
+++ b/src/Qir/Execution/Tools/Executable/QirExecutableGenerator.cs
@@ -1,20 +1,16 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
+using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Quantum.Qir.Utility;
-namespace Microsoft.Quantum.Qir.Executable
+namespace Microsoft.Quantum.Qir.Tools.Executable
{
- public class QirExecutableGenerator : IQirExecutableGenerator
+ internal class QirExecutableGenerator : IQirExecutableGenerator
{
- private static readonly string[] LibrariesToLink = {
- "Microsoft.Quantum.Qir.Runtime",
- "Microsoft.Quantum.Qir.QSharp.Foundation",
- "Microsoft.Quantum.Qir.QSharp.Core"
- };
private readonly IClangClient clangClient;
private readonly ILogger logger;
@@ -24,7 +20,7 @@ public QirExecutableGenerator(IClangClient clangClient, ILogger logger)
this.logger = logger;
}
- public async Task GenerateExecutableAsync(FileInfo executableFile, DirectoryInfo sourceDirectory, DirectoryInfo libraryDirectory, DirectoryInfo includeDirectory)
+ public async Task GenerateExecutableAsync(FileInfo executableFile, DirectoryInfo sourceDirectory, DirectoryInfo libraryDirectory, DirectoryInfo includeDirectory, IList linkLibraries)
{
// Wrap in a Task.Run because FileInfo methods are not asynchronous.
await Task.Run(async () =>
@@ -42,7 +38,7 @@ await Task.Run(async () =>
}
var inputFiles = sourceDirectory.GetFiles().Select(fileInfo => fileInfo.FullName).ToArray();
- await clangClient.CreateExecutableAsync(inputFiles, LibrariesToLink, libraryDirectory.FullName, includeDirectory.FullName, executableFile.FullName);
+ await clangClient.CreateExecutableAsync(inputFiles, linkLibraries.ToArray(), libraryDirectory.FullName, includeDirectory.FullName, executableFile.FullName);
});
}
diff --git a/src/Qir/Execution/Tools/Executable/QirFullStateExecutable.cs b/src/Qir/Execution/Tools/Executable/QirFullStateExecutable.cs
new file mode 100644
index 00000000000..03362d370a6
--- /dev/null
+++ b/src/Qir/Execution/Tools/Executable/QirFullStateExecutable.cs
@@ -0,0 +1,32 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Collections.Generic;
+using System.IO;
+using Microsoft.Quantum.Qir.Tools.Driver;
+using Microsoft.Quantum.Qir.Utility;
+
+namespace Microsoft.Quantum.Qir.Tools.Executable
+{
+ ///
+ /// Class to create and run QIR-based executables that use the full-state simulator.
+ ///
+ public class QirFullStateExecutable : QirExecutable
+ {
+ public QirFullStateExecutable(FileInfo executableFile, byte[] qirBytecode, ILogger logger = null)
+ : base(executableFile,
+ qirBytecode,
+ new QirFullStateDriverGenerator(),
+ logger)
+ {
+ }
+
+ public override IList LinkLibraries => new List {
+ "Microsoft.Quantum.Qir.Runtime",
+ "Microsoft.Quantum.Qir.QSharp.Foundation",
+ "Microsoft.Quantum.Qir.QSharp.Core"
+ };
+
+ public override string DriverFileExtension => "cpp";
+ }
+}
diff --git a/src/Qir/Execution/Tools/Executable/QuantumExecutableRunner.cs b/src/Qir/Execution/Tools/Executable/QuantumExecutableRunner.cs
new file mode 100644
index 00000000000..987d6212799
--- /dev/null
+++ b/src/Qir/Execution/Tools/Executable/QuantumExecutableRunner.cs
@@ -0,0 +1,40 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Diagnostics;
+using System.IO;
+using System.Threading.Tasks;
+using Microsoft.Quantum.Qir.Utility;
+
+namespace Microsoft.Quantum.Qir.Tools.Executable
+{
+ internal class QuantumExecutableRunner : IQuantumExecutableRunner
+ {
+ private readonly ILogger logger;
+
+ public QuantumExecutableRunner(ILogger logger)
+ {
+ this.logger = logger;
+ }
+
+ public async Task RunExecutableAsync(FileInfo executableFile, Stream stream, string arguments)
+ {
+ logger.LogInfo($"Invoking executable {executableFile.FullName} with the following arguments: {arguments}");
+ using var process = new Process();
+ process.StartInfo = new ProcessStartInfo
+ {
+ FileName = executableFile.FullName,
+ Arguments = arguments,
+ RedirectStandardOutput = true,
+ };
+
+ process.EnableRaisingEvents = true;
+ process.Start();
+ var output = await process.StandardOutput.ReadToEndAsync();
+ process.WaitForExit();
+ using var streamWriter = new StreamWriter(stream);
+ await streamWriter.WriteAsync(output);
+ logger.LogInfo($"Executable has finished running. Result code: {process.ExitCode}");
+ }
+ }
+}
diff --git a/src/Qir/Execution/Tools/Microsoft.Quantum.Qir.Tools.csproj b/src/Qir/Execution/Tools/Microsoft.Quantum.Qir.Tools.csproj
index 5ad95e9541e..06ca9571b79 100644
--- a/src/Qir/Execution/Tools/Microsoft.Quantum.Qir.Tools.csproj
+++ b/src/Qir/Execution/Tools/Microsoft.Quantum.Qir.Tools.csproj
@@ -11,7 +11,7 @@
-
+
-
+
diff --git a/src/Qir/Execution/Tools/QirExecutable.cs b/src/Qir/Execution/Tools/QirExecutable.cs
deleted file mode 100644
index de641f4b174..00000000000
--- a/src/Qir/Execution/Tools/QirExecutable.cs
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License.
-
-using Microsoft.Quantum.QsCompiler.BondSchemas.EntryPoint;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Threading.Tasks;
-
-namespace Microsoft.Quantum.Qir.Tools
-{
- ///
- /// Base for creating and running QIR-based executables.
- ///
- public abstract class QirExecutable
- {
- private readonly EntryPointOperation EntryPointOperation;
- private readonly byte[] QirBytecode;
-
- ///
- /// Constructor for the QirExecutable class.
- ///
- /// Object that provides data to specify which entry-point to use for building and running a QIR-based executable.
- /// QIR bytecode used to build the executable.
- public QirExecutable(EntryPointOperation entryPoint, byte[] qirBytecode)
- {
- this.EntryPointOperation = entryPoint;
- this.QirBytecode = qirBytecode;
- }
-
- ///
- /// Creates a QIR-based executable.
- ///
- /// Directory where the libraries to link to are located.
- /// Directory where the headers needed for compilation are located.
- /// File to write the executable to.
- public Task BuildAsync(DirectoryInfo libraryDirectory, DirectoryInfo includeDirectory, FileInfo executable)
- {
- throw new NotImplementedException();
- }
-
- // TODO: How arguments are passed to this API will change.
- public Task RunAsync(FileInfo executable, DirectoryInfo librariesDirectory, IList arguments)
- {
- throw new NotImplementedException();
- }
-
- // TODO: To be used by BuildAsync.
- protected abstract Task GenerateDriverAsync(Stream driver);
-
- // TODO: To be used by RunAsync.
- // TODO: How arguments are passed to this API will change.
- protected abstract string GetCommandLineArguments(IList arguments);
-
- // TODO: To be used by BuildAsync.
- protected abstract IList GetLinkLibraries();
- }
-}
diff --git a/src/Qir/Execution/Tools/QirFullStateExecutable.cs b/src/Qir/Execution/Tools/QirFullStateExecutable.cs
deleted file mode 100644
index 882572810bc..00000000000
--- a/src/Qir/Execution/Tools/QirFullStateExecutable.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License.
-
-using Microsoft.Quantum.QsCompiler.BondSchemas.EntryPoint;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Threading.Tasks;
-
-namespace Microsoft.Quantum.Qir.Tools
-{
- ///
- /// Class to create and run QIR-based executables that use the full-state simulator.
- ///
- public class QirFullStateExecutable : QirExecutable
- {
- ///
- public QirFullStateExecutable(EntryPointOperation entryPoint, byte[] qirBytecode) :
- base(entryPoint, qirBytecode)
- {
- }
-
- protected override Task GenerateDriverAsync(Stream driver)
- {
- throw new NotImplementedException();
- }
-
- // TODO: How arguments are passed to this API will change.
- protected override string GetCommandLineArguments(IList arguments)
- {
- throw new NotImplementedException();
- }
-
- protected override IList GetLinkLibraries()
- {
- throw new NotImplementedException();
- }
- }
-}
diff --git a/src/Qir/Controller/Utility/Clock.cs b/src/Qir/Execution/Tools/Utility/Clock.cs
similarity index 100%
rename from src/Qir/Controller/Utility/Clock.cs
rename to src/Qir/Execution/Tools/Utility/Clock.cs
diff --git a/src/Qir/Controller/Utility/IClock.cs b/src/Qir/Execution/Tools/Utility/IClock.cs
similarity index 100%
rename from src/Qir/Controller/Utility/IClock.cs
rename to src/Qir/Execution/Tools/Utility/IClock.cs
diff --git a/src/Qir/Controller/Utility/ILogger.cs b/src/Qir/Execution/Tools/Utility/ILogger.cs
similarity index 100%
rename from src/Qir/Controller/Utility/ILogger.cs
rename to src/Qir/Execution/Tools/Utility/ILogger.cs
diff --git a/src/Qir/Controller/Utility/Logger.cs b/src/Qir/Execution/Tools/Utility/Logger.cs
similarity index 100%
rename from src/Qir/Controller/Utility/Logger.cs
rename to src/Qir/Execution/Tools/Utility/Logger.cs