Skip to content
This repository was archived by the owner on Jan 12, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 94 additions & 0 deletions src/Qir/Execution/Tools/EntryPointOperationLoader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.Quantum.Qir.Serialization;
using Microsoft.Quantum.QsCompiler;
using Microsoft.Quantum.QsCompiler.SyntaxTokens;
using Microsoft.Quantum.QsCompiler.SyntaxTree;
using Microsoft.Quantum.QsCompiler.QIR;

namespace Microsoft.Quantum.Qir.Tools
{
using QsTypeKind = QsTypeKind<ResolvedType, UserDefinedType, QsTypeParameter, CallableInformation>;

internal static class EntryPointLoader
{
/// <summary>
/// Loads the entry point operations found in the syntax tree included as a resource from <paramref name="assemblyFileInfo"/>.
/// </summary>
/// <param name="assemblyFileInfo">The file info of a .NET DLL from which to load entry point operations from.</param>
/// <returns>
/// A list of entry point operation objects representing the QIR entry point operations.
/// </returns>
/// <exception cref="FileNotFoundException"><paramref name="assemblyFileInfo"/> does not exist.</exception>
/// <exception cref="ArgumentException"><paramref name="assemblyFileInfo"/> does not contain a Q# syntax tree.</exception>
/// <exception cref="ArgumentException">Encounters invalid parameters for an entry point.</exception>
public static IList<EntryPointOperation> LoadEntryPointOperations(FileInfo assemblyFileInfo)
{
if (!AssemblyLoader.LoadReferencedAssembly(assemblyFileInfo.FullName, out var compilation))
{
throw new ArgumentException("Unable to read the Q# syntax tree from the given DLL.");
}

return GenerateEntryPointOperations(compilation);
}

private static IList<EntryPointOperation> GenerateEntryPointOperations(QsCompilation compilation)
{
var globals = compilation.Namespaces.GlobalCallableResolutions();

return compilation.EntryPoints.Select(ep => new EntryPointOperation()
{
Name = NameGeneration.InteropFriendlyWrapperName(ep),
Parameters = GetParams(globals[ep]),
}).ToList();
}

private static List<Parameter> GetParams(QsCallable callable)
{
return SyntaxGenerator.ExtractItems(callable.ArgumentTuple)
.Where(sym => !sym.Type.Resolution.IsUnitType)
.Select(sym => MakeParameter(sym))
.ToList();
}

private static Parameter MakeParameter(LocalVariableDeclaration<QsLocalSymbol> parameter)
{
var type = MapResolvedTypeToDataType(parameter.Type);
var arrayType = parameter.Type.Resolution is QsTypeKind.ArrayType innerType
? (DataType?)MapResolvedTypeToDataType(innerType.Item)
: null;

if (arrayType == DataType.ArrayType)
{
throw new ArgumentException("Multi-dimensional arrays are not supported types of entry point parameters.");
}

return new Parameter()
{
Name = parameter.VariableName is QsLocalSymbol.ValidName name
? name.Item
: throw new ArgumentException("Encountered invalid name for parameter."),
Type = type,
ArrayType = arrayType,
};
}

private static DataType MapResolvedTypeToDataType(ResolvedType rt) => rt.Resolution.Tag switch
{
QsTypeKind.Tags.Bool => DataType.BoolType,
QsTypeKind.Tags.Int => DataType.IntegerType,
QsTypeKind.Tags.Double => DataType.DoubleType,
QsTypeKind.Tags.Pauli => DataType.PauliType,
QsTypeKind.Tags.Range => DataType.RangeType,
QsTypeKind.Tags.Result => DataType.ResultType,
QsTypeKind.Tags.String => DataType.StringType,
QsTypeKind.Tags.ArrayType => DataType.ArrayType,
_ => throw new ArgumentException($"Invalid type ({rt.Resolution.Tag}) for entry point parameter"),
};
}
}
22 changes: 11 additions & 11 deletions src/Qir/Execution/Tools/Executable/QirExecutable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ namespace Microsoft.Quantum.Qir.Tools.Executable
public abstract class QirExecutable : IQirExecutable
{
private const string DriverFileName = "driver";
private const string BytecodeFileName = "qir.bc";
private const string BitcodeFileName = "qir.bc";

public virtual string SourceDirectoryPath => "src";
public abstract string DriverFileExtension { get; }
Expand All @@ -27,26 +27,26 @@ public abstract class QirExecutable : IQirExecutable

protected FileInfo ExecutableFile { get; }

private readonly byte[] qirBytecode;
private readonly byte[] qirBitcode;
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)
public QirExecutable(FileInfo executableFile, byte[] qirBitcode, IQirDriverGenerator driverGenerator, ILogger logger = null)
: this(executableFile,
qirBytecode,
qirBitcode,
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)
internal QirExecutable(FileInfo executableFile, byte[] qirBitcode, ILogger logger, IQirDriverGenerator driverGenerator, IQirExecutableGenerator executableGenerator, IQuantumExecutableRunner runner)
{
ExecutableFile = executableFile;
this.qirBytecode = qirBytecode;
this.qirBitcode = qirBitcode;
this.logger = logger;
this.runner = runner;
this.driverGenerator = driverGenerator;
Expand All @@ -73,13 +73,13 @@ public async Task BuildAsync(EntryPointOperation entryPoint, IList<DirectoryInfo
}
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())
// Create bitcode file.
var bitcodeFile = new FileInfo(Path.Combine(sourceDirectory.FullName, BitcodeFileName));
using (var bitcodeFileStream = bitcodeFile.OpenWrite())
{
await bytecodeFileStream.WriteAsync(qirBytecode);
await bitcodeFileStream.WriteAsync(qirBitcode);
}
logger.LogInfo($"Created bytecode file at {bytecodeFile.FullName}.");
logger.LogInfo($"Created bitcode file at {bitcodeFile.FullName}.");
await executableGenerator.GenerateExecutableAsync(ExecutableFile, sourceDirectory, libraryDirectories.Concat(this.LibraryDirectories).ToList(), includeDirectories.Concat(this.HeaderDirectories).ToList(), LinkLibraries);
}

Expand Down
4 changes: 2 additions & 2 deletions src/Qir/Execution/Tools/Executable/QirFullStateExecutable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ public class QirFullStateExecutable : QirExecutable

public override IList<DirectoryInfo> LibraryDirectories { get; } = new List<DirectoryInfo>();

public QirFullStateExecutable(FileInfo executableFile, byte[] qirBytecode, ILogger logger = null)
public QirFullStateExecutable(FileInfo executableFile, byte[] qirBitcode, ILogger logger = null)
: base(executableFile,
qirBytecode,
qirBitcode,
new QirFullStateDriverGenerator(),
logger)
{
Expand Down
6 changes: 3 additions & 3 deletions src/Qir/Execution/Tools/QirTools.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,17 @@ public static async Task BuildFromQSharpDll(
DirectoryInfo executablesDirectory)
{
using var qirContentStream = new MemoryStream();
if (!AssemblyLoader.LoadQirByteCode(qsharpDll, qirContentStream))
if (!AssemblyLoader.LoadQirBitcode(qsharpDll, qirContentStream))
{
throw new ArgumentException("The given DLL does not contain QIR byte code.");
throw new ArgumentException("The given DLL does not contain QIR bitcode.");
}

if (!executablesDirectory.Exists)
{
executablesDirectory.Create();
}

var tasks = EntryPointOperationLoader.LoadEntryPointOperations(qsharpDll).Select(entryPointOp =>
var tasks = EntryPointLoader.LoadEntryPointOperations(qsharpDll).Select(entryPointOp =>
{
var exeFileInfo = new FileInfo(Path.Combine(executablesDirectory.FullName, $"{entryPointOp.Name}.exe"));
var exe = new QirFullStateExecutable(exeFileInfo, qirContentStream.ToArray());
Expand Down