diff --git a/src/QsCompiler/Compiler/RewriteSteps/QirGeneration.cs b/src/QsCompiler/Compiler/RewriteSteps/QirGeneration.cs
index 656a66dc16..9c573fb8de 100644
--- a/src/QsCompiler/Compiler/RewriteSteps/QirGeneration.cs
+++ b/src/QsCompiler/Compiler/RewriteSteps/QirGeneration.cs
@@ -68,7 +68,7 @@ public bool PreconditionVerification(QsCompilation compilation)
///
public bool Transformation(QsCompilation compilation, out QsCompilation transformed)
{
- var generator = new Generator(compilation, new Configuration());
+ var generator = new Generator(compilation);
generator.Apply();
generator.Emit(this.outputFile);
transformed = compilation;
diff --git a/src/QsCompiler/Core/SyntaxGenerator.fs b/src/QsCompiler/Core/SyntaxGenerator.fs
index f6361bc0ee..d067611f58 100644
--- a/src/QsCompiler/Core/SyntaxGenerator.fs
+++ b/src/QsCompiler/Core/SyntaxGenerator.fs
@@ -341,6 +341,17 @@ module SyntaxGenerator =
let QubitArrayType = Qubit |> ResolvedType.New |> ArrayType |> ResolvedType.New
+ /// Recursively extracts and returns all tuple items in the given tuple.
+ let ExtractInnerItems (this: ITuple) =
+ let rec extractAll =
+ function
+ | Tuple items -> items |> Seq.collect extractAll
+ | Item item -> seq { yield item }
+ | Missing -> ArgumentException "missing item in tuple" |> raise
+ | _ -> ArgumentException "invalid item in tuple" |> raise
+
+ this |> extractAll
+
/// Given a QsTuple, recursively extracts and returns all of its items.
let ExtractItems (this: QsTuple<_>) = this.Items.ToImmutableArray()
diff --git a/src/QsCompiler/QirGeneration/Configuration.cs b/src/QsCompiler/QirGeneration/Configuration.cs
deleted file mode 100644
index 0ea10ab488..0000000000
--- a/src/QsCompiler/QirGeneration/Configuration.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License.
-
-using System.Collections.Generic;
-using System.Collections.Immutable;
-using Microsoft.Quantum.QIR;
-
-namespace Microsoft.Quantum.QsCompiler.QIR
-{
- ///
- /// Class that contains all configurable settings for the QIR emission.
- ///
- public class Configuration
- {
- private static readonly ImmutableDictionary ClangInteropTypeMapping =
- ImmutableDictionary.CreateRange(new Dictionary
- {
- [TypeNames.Result] = "class.RESULT",
- [TypeNames.Array] = "struct.quantum::Array",
- [TypeNames.Callable] = "struct.quantum::Callable",
- [TypeNames.Tuple] = "struct.quantum::TupleHeader",
- [TypeNames.Qubit] = "class.QUBIT"
- });
-
- internal readonly ImmutableDictionary InteropTypeMapping;
-
- ///
- /// Constructs a class instance storing the configurable settings for QIR emission.
- ///
- ///
- /// Optional parameter that maps the name of a QIR type to the name of the corresponding interop type.
- /// The mapping specifies with which type names the QIR types are replaced with
- /// when generating the interop wrappers and entry point(s).
- ///
- public Configuration(Dictionary? interopTypeMapping = null)
- {
- this.InteropTypeMapping = interopTypeMapping != null
- ? interopTypeMapping.ToImmutableDictionary()
- : ClangInteropTypeMapping;
- }
- }
-}
diff --git a/src/QsCompiler/QirGeneration/Context.cs b/src/QsCompiler/QirGeneration/Context.cs
index 1ace79e8e4..add969def2 100644
--- a/src/QsCompiler/QirGeneration/Context.cs
+++ b/src/QsCompiler/QirGeneration/Context.cs
@@ -41,43 +41,8 @@ static GenerationContext()
LibContext.RegisterTarget(CodeGenTarget.Native);
}
- ///
- /// This type is used to map Q# types to interop-friendly types.
- ///
- private class ArgMapping
- {
- internal readonly string BaseName;
-
- ///
- /// The first item contains the array element type, and the second item contains the array count name.
- /// If is not null, then is null.
- ///
- private readonly (ResolvedType, string)? arrayInfo;
-
- internal bool IsArray => this.arrayInfo != null;
- internal ResolvedType ArrayElementType => this.arrayInfo?.Item1 ?? throw new InvalidOperationException("not an array");
- internal string ArrayCountName => this.arrayInfo?.Item2 ?? throw new InvalidOperationException("not an array");
-
- private ArgMapping(string baseName, (ResolvedType, string)? arrayInfo = null)
- {
- this.BaseName = baseName;
- this.arrayInfo = arrayInfo;
- }
-
- internal static ArgMapping Create(string baseName) =>
- new ArgMapping(baseName);
-
- internal ArgMapping WithArrayInfo(ResolvedType arrayType, string arrayCountName) =>
- new ArgMapping(this.BaseName, arrayInfo: (arrayType, arrayCountName));
- }
-
#region Member variables
- ///
- /// The configuration for QIR generation.
- ///
- public readonly Configuration Config;
-
///
/// The context used for QIR generation.
///
@@ -91,12 +56,6 @@ internal ArgMapping WithArrayInfo(ResolvedType arrayType, string arrayCountName)
///
public readonly BitcodeModule Module;
- ///
- /// The module used for constructing functions to facilitate interoperability.
- ///
- ///
- public readonly BitcodeModule InteropModule;
-
///
/// The used QIR types.
///
@@ -151,7 +110,6 @@ internal ArgMapping WithArrayInfo(ResolvedType arrayType, string arrayCountName)
private readonly Dictionary uniqueLocalNames = new Dictionary();
private readonly Dictionary uniqueGlobalNames = new Dictionary();
- private readonly Dictionary interopType = new Dictionary();
private readonly List<(IrFunction, Action>)> liftedPartialApplications = new List<(IrFunction, Action>)>();
private readonly Dictionary callableTables = new Dictionary();
private readonly Dictionary memoryManagementTables = new Dictionary();
@@ -187,14 +145,11 @@ internal void EndBranch() =>
/// 2.) the runtime library needs to be initialized by calling , and
/// 3.) the quantum instructions set needs to be registered by calling .
///
- /// The compilation unit for which QIR is generated.
- /// The configuration for QIR generation.
- internal GenerationContext(IEnumerable syntaxTree, Configuration config)
+ /// The syntax tree for which QIR is generated.
+ internal GenerationContext(IEnumerable syntaxTree)
{
- this.Config = config;
this.Context = new Context();
this.Module = this.Context.CreateBitcodeModule();
- this.InteropModule = this.Context.CreateBitcodeModule("bridge");
this.Types = new Types(this.Context);
this.Constants = new Constants(this.Context, this.Module, this.Types);
@@ -279,6 +234,7 @@ public static string FunctionName(QsQualifiedName fullName, QsSpecializationKind
/// Generates a mangled name for a callable specialization wrapper.
/// Wrapper names are the mangled specialization name followed by double underscore and "wrapper".
///
+ /// The callable's qualified name
/// The specialization kind.
/// The mangled name for the wrapper.
public static string FunctionWrapperName(QsQualifiedName fullName, QsSpecializationKind kind) =>
@@ -322,8 +278,8 @@ internal static bool TryGetTargetInstructionName(QsCallable callable, [MaybeNull
///
public void InitializeRuntimeLibrary()
{
- // int library functions
- this.runtimeLibrary.AddFunction(RuntimeLibrary.IntPower, this.Types.Int, this.Types.Int, this.Context.Int32Type);
+ // Q# specific helpers
+ this.runtimeLibrary.AddFunction(RuntimeLibrary.HeapAllocate, this.Context.Int8Type.CreatePointerType(), this.Context.Int64Type);
// result library functions
this.runtimeLibrary.AddFunction(RuntimeLibrary.ResultUpdateReferenceCount, this.Context.VoidType, this.Types.Result, this.Types.Int);
@@ -331,6 +287,8 @@ public void InitializeRuntimeLibrary()
// string library functions
this.runtimeLibrary.AddFunction(RuntimeLibrary.StringCreate, this.Types.String, this.Context.Int32Type, this.Types.DataArrayPointer);
+ this.runtimeLibrary.AddFunction(RuntimeLibrary.StringGetLength, this.Context.Int32Type, this.Types.String);
+ this.runtimeLibrary.AddFunction(RuntimeLibrary.StringGetData, this.Types.DataArrayPointer, this.Types.String);
this.runtimeLibrary.AddFunction(RuntimeLibrary.StringUpdateReferenceCount, this.Context.VoidType, this.Types.String, this.Types.Int);
this.runtimeLibrary.AddFunction(RuntimeLibrary.StringConcatenate, this.Types.String, this.Types.String, this.Types.String);
this.runtimeLibrary.AddFunction(RuntimeLibrary.StringEqual, this.Context.BoolType, this.Types.String, this.Types.String);
@@ -373,16 +331,12 @@ public void InitializeRuntimeLibrary()
this.runtimeLibrary.AddFunction(RuntimeLibrary.TupleCopy, this.Types.Tuple, this.Types.Tuple, this.Context.BoolType);
// array library functions
- this.runtimeLibrary.AddVarArgsFunction(RuntimeLibrary.ArrayCreate, this.Types.Array, this.Context.Int32Type, this.Context.Int32Type);
- this.runtimeLibrary.AddVarArgsFunction(RuntimeLibrary.ArrayGetElementPtr, this.Context.Int8Type.CreatePointerType(), this.Types.Array);
- // TODO: figure out how to call a varargs function and get rid of these two functions
this.runtimeLibrary.AddFunction(RuntimeLibrary.ArrayCreate1d, this.Types.Array, this.Context.Int32Type, this.Context.Int64Type);
this.runtimeLibrary.AddFunction(RuntimeLibrary.ArrayGetElementPtr1d, this.Context.Int8Type.CreatePointerType(), this.Types.Array, this.Context.Int64Type);
this.runtimeLibrary.AddFunction(RuntimeLibrary.ArrayUpdateAliasCount, this.Context.VoidType, this.Types.Array, this.Types.Int);
this.runtimeLibrary.AddFunction(RuntimeLibrary.ArrayUpdateReferenceCount, this.Context.VoidType, this.Types.Array, this.Types.Int);
this.runtimeLibrary.AddFunction(RuntimeLibrary.ArrayCopy, this.Types.Array, this.Types.Array, this.Context.BoolType);
this.runtimeLibrary.AddFunction(RuntimeLibrary.ArrayConcatenate, this.Types.Array, this.Types.Array, this.Types.Array);
- this.runtimeLibrary.AddFunction(RuntimeLibrary.ArraySlice, this.Types.Array, this.Context.Int32Type, this.Types.Array, this.Types.Range);
this.runtimeLibrary.AddFunction(RuntimeLibrary.ArraySlice1d, this.Types.Array, this.Types.Array, this.Types.Range, this.Context.BoolType);
this.runtimeLibrary.AddFunction(RuntimeLibrary.ArrayGetSize1d, this.Context.Int64Type, this.Types.Array);
@@ -435,214 +389,29 @@ public void RegisterQuantumInstructionSet()
}
///
- /// Writes the current content to the output file.
- ///
- public void Emit(string fileName, bool overwrite = true, bool generateInteropWrappers = false)
- {
- var bridgeFile = Path.Combine(
- Path.GetDirectoryName(fileName),
- Path.GetFileNameWithoutExtension(fileName) + "_bridge.ll");
- var existing = new[]
- {
- File.Exists(fileName) ? fileName : null,
- generateInteropWrappers && File.Exists(bridgeFile) ? bridgeFile : null,
- };
-
- if (!overwrite && existing.Any(s => s != null))
- {
- var argStr = string.Join(", ", existing.Where(s => s == null));
- throw new ArgumentException($"The following file(s) already exist(s): {argStr}");
- }
-
- this.GenerateRequiredFunctions();
-
- if (!this.Module.Verify(out string validationErrors))
- {
- File.WriteAllText(fileName, $"LLVM errors:{Environment.NewLine}{validationErrors}");
- }
-
- if (!this.Module.WriteToTextFile(fileName, out string errorMessage))
- {
- throw new IOException(errorMessage);
- }
-
- var bitcodeFileName = Path.ChangeExtension(fileName, "bc");
- this.Module.WriteToFile(bitcodeFileName);
-
- // Generate the wrappers for the runtime library that were used, if requested
- if (generateInteropWrappers)
- {
- foreach (var kvp in this.runtimeLibrary)
- {
- this.GenerateInterop(kvp.Value, kvp.Key);
- }
-
- foreach (var c in this.globalCallables.Values)
- {
- if (TryGetTargetInstructionName(c, out var name))
- {
- var func = this.quantumInstructionSet.GetOrCreateFunction(name);
- this.GenerateInterop(func, name);
- }
- }
-
- if (!this.InteropModule.Verify(out string bridgeValidationErrors))
- {
- File.WriteAllText(bridgeFile, $"LLVM errors:{Environment.NewLine}{bridgeValidationErrors}");
- }
- else if (!this.InteropModule.WriteToTextFile(bridgeFile, out string bridgeError))
- {
- throw new IOException(bridgeError);
- }
-
- var bitcodeBridgeFile = Path.ChangeExtension(bridgeFile, "bc");
- this.InteropModule.WriteToFile(bitcodeBridgeFile);
- }
- }
-
- #endregion
-
- #region Interop utils
-
- ///
- /// Generates an interop-friendly wrapper around the Q# entry point using the configured type mapping.
+ /// Generates an interop-friendly wrapper around the callable with the given name such that it can be invoked
+ /// from within native code without relying on the QIR runtime or adhering to the QIR specification.
+ /// See and
+ /// for more detail.
+ ///
+ /// If an attribute name is specified, adds an attribute with the given name to the created wrapper.
+ /// If no wrapper needed to be created because the signature of the callable is interop-friendly,
+ /// adds the attribute to the existing function.
///
- /// The namespace-qualified name of the Q# entry point
- public void GenerateEntryPoint(QsQualifiedName qualifiedName)
+ /// The function name to give the wrapper.
+ /// The fully qualified name of the Q# callable to create a wrapper for.
+ /// Optionally the name of the attribute to attach.
+ /// No callable with the given name exists in the compilation.
+ public void CreateInteropWrapper(string wrapperName, QsQualifiedName qualifiedName, string? attributeName = null)
{
- // Unfortunately this is different enough from all of the other type mapping we do to require
- // an actual different routine. Blech...
- IEnumerable MapType(ArgumentTuple t, List nameList, List mappingList)
- {
- if (t is ArgumentTuple.QsTuple tuple)
- {
- foreach (var inner in tuple.Item)
- {
- foreach (var mapped in MapType(inner, nameList, mappingList))
- {
- yield return mapped;
- }
- }
- }
- else if (t is ArgumentTuple.QsTupleItem item && item.Item.VariableName is QsLocalSymbol.ValidName varName)
- {
- var baseName = varName.Item;
- var map = ArgMapping.Create(baseName);
- switch (item.Item.Type.Resolution)
- {
- case ResolvedTypeKind.ArrayType elementType:
- yield return this.Context.Int64Type;
- var elementTypeRef = this.LlvmTypeFromQsharpType(elementType.Item);
- yield return elementTypeRef.CreatePointerType();
- var arrayCountName = $"{baseName}__count";
- nameList.Add(arrayCountName);
- nameList.Add(baseName);
- map = map.WithArrayInfo(elementType.Item, arrayCountName);
- mappingList.Add(map);
- break;
- default:
- yield return this.LlvmTypeFromQsharpType(item.Item.Type);
- nameList.Add(baseName);
- mappingList.Add(map);
- break;
- }
- }
- }
-
if (this.TryGetFunction(qualifiedName, QsSpecializationKind.QsBody, out IrFunction? func)
&& this.TryGetGlobalCallable(qualifiedName, out QsCallable? callable))
{
- var entryPointName = EntryPointName(qualifiedName);
- var entryPointAttribute = this.Context.CreateAttribute(AttributeNames.EntryPoint);
-
- // Check to see if the arg list needs mapping to interop-friendly types
- var mappedNameList = new List();
- var mappingList = new List();
- var mappedResultType = this.MapToInteropType(func.ReturnType);
- var mappedArgList = MapType(callable.ArgumentTuple, mappedNameList, mappingList);
-
- var entryPointType = this.Context.GetFunctionType(mappedResultType, mappedArgList);
- if (!entryPointType.Equals(func.Signature))
+ var wrapper = Interop.GenerateWrapper(this, wrapperName, callable.ArgumentTuple, callable.Signature.ReturnType, func);
+ if (attributeName != null)
{
- this.StartFunction();
- this.CurrentFunction = this.Module.CreateFunction(entryPointName, entryPointType);
- var namedValues = new Dictionary();
- for (var i = 0; i < mappedNameList.Count; i++)
- {
- this.CurrentFunction.Parameters[i].Name = mappedNameList[i];
- namedValues[this.CurrentFunction.Parameters[i].Name] = this.CurrentFunction.Parameters[i];
- }
- var entryBlock = this.CurrentFunction.AppendBasicBlock("entry");
- this.SetCurrentBlock(entryBlock);
-
- // Build the argument list for the inner function
- var argValueList = new List();
- foreach (var mapping in mappingList)
- {
- if (mapping.IsArray)
- {
- var length = namedValues[mapping.ArrayCountName];
- ArrayValue array = this.Values.CreateArray(length, mapping.ArrayElementType);
- argValueList.Add(array.OpaquePointer);
-
- // Fill in the array if the length is >0.
- // Since the QIR array is new, we assume we can use memcpy. // FIXME: THIS ASSUMPTION IS NOT VALID EITHER...!
- var copyBlock = this.CurrentFunction.AppendBasicBlock("copy");
- var nextBlock = this.CurrentFunction.AppendBasicBlock("next");
- var cond = this.CurrentBuilder.Compare(IntPredicate.SignedGreaterThan, length, this.Context.CreateConstant(0L));
- this.CurrentBuilder.Branch(cond, copyBlock, nextBlock);
-
- this.SetCurrentBlock(copyBlock);
- var getArrayItem = this.GetOrCreateRuntimeFunction(RuntimeLibrary.ArrayGetElementPtr1d);
-
- var givenArray = namedValues[mapping.BaseName];
- var givenArrayPtr = this.CurrentBuilder.PointerToInt(givenArray, this.Context.Int64Type);
- var givenArrElementType = Types.PointerElementType(givenArray);
- var givenArrElementSize = this.ComputeSizeForType(givenArrElementType);
-
- ////
- // We need to populate the array
- var start = this.Context.CreateConstant(0L);
- var end = this.CurrentBuilder.Sub(array.Length, this.Context.CreateConstant(1L));
- void PopulateItem(Value index)
- {
- // We need to make sure that the reference count for the built item is increased by 1.
- var arrayElementType = this.LlvmTypeFromQsharpType(mapping.ArrayElementType);
- var offset = this.CurrentBuilder.Mul(index, givenArrElementSize);
- var elementPointer = this.CurrentBuilder.Add(givenArrayPtr, offset);
-
- var loaded = this.CurrentBuilder.Load(arrayElementType, this.CurrentBuilder.IntToPointer(elementPointer, (IPointerType)givenArray.NativeType));
- var element = this.Values.From(loaded, mapping.ArrayElementType); // FIXME: THIS IS NOT CORRECT IF WE HAVE ARRAY OF ARRAY
- array.GetArrayElementPointer(index).StoreValue(element);
- }
- this.IterateThroughRange(start, null, end, PopulateItem);
- ////
-
- this.CurrentBuilder.Branch(nextBlock);
- this.SetCurrentBlock(nextBlock);
- }
- else
- {
- argValueList.Add(namedValues[mapping.BaseName]);
- }
- }
-
- Value result = this.CurrentBuilder.Call(func, argValueList);
- var mappedResult = mappedResultType.IsVoid || mappedResultType == func.ReturnType
- ? this.Values.From(result, callable.Signature.ReturnType)
- // FIME: WHY WOULD THAT BE OK; WE NEED TO DO THE SAME TRANSLATION AS FOR THE INPUT...
- : this.Values.From(this.CurrentBuilder.BitCast(result, mappedResultType), callable.Signature.ReturnType); // FIXME: NOT CORRECT
- this.AddReturn(mappedResult, mappedResultType.IsVoid);
- this.EndFunction();
-
- // Mark the function as an entry point
- this.CurrentFunction.AddAttributeAtIndex(FunctionAttributeIndex.Function, entryPointAttribute);
- }
- else
- {
- this.Module.AddAlias(func, entryPointName).Linkage = Linkage.External;
- // Mark the function as an entry point
- func.AddAttributeAtIndex(FunctionAttributeIndex.Function, entryPointAttribute);
+ var attribute = this.Context.CreateAttribute(attributeName);
+ wrapper.AddAttributeAtIndex(FunctionAttributeIndex.Function, attribute);
}
}
else
@@ -652,128 +421,25 @@ void PopulateItem(Value index)
}
///
- /// Generates a stub implementation for a runtime function or quantum instruction using the specified type
- /// mappings for interoperability. Note that the create functions go into a separate module from the other QIR code.
+ /// Writes the current content to the output file.
///
- /// The function to generate a stub for
- /// The function that the stub should call
- private void GenerateInterop(IrFunction func, string baseName)
+ public void Emit(string fileName, bool overwrite = true)
{
- // TODO: why do we need both GenerateEntryPoint and GenerateInterop?
-
- func = this.InteropModule.CreateFunction(func.Name, func.Signature);
-
- var mappedResultType = this.MapToInteropType(func.ReturnType);
- var argTypes = func.Parameters.Select(p => p.NativeType).ToArray();
- var mappedArgTypes = argTypes.Select(this.MapToInteropType).ToArray();
-
- var interopFunction = this.InteropModule.CreateFunction(
- baseName,
- this.Context.GetFunctionType(mappedResultType, mappedArgTypes));
-
- for (var i = 0; i < func.Parameters.Count; i++)
+ if (!overwrite && File.Exists(fileName))
{
- func.Parameters[i].Name = $"arg{i + 1}";
+ throw new ArgumentException($"The file \"{fileName}\" already exist(s).");
}
- var builder = new InstructionBuilder(func.AppendBasicBlock("entry"));
- var implArgs = Enumerable.Range(0, argTypes.Length)
- .Select(index => argTypes[index] == mappedArgTypes[index]
- ? func.Parameters[index]
- : builder.BitCast(func.Parameters[index], mappedArgTypes[index]))
- .ToArray();
- var interopReturnValue = builder.Call(interopFunction, implArgs);
- if (func.ReturnType == this.Context.VoidType)
- {
- builder.Return();
- }
- else if (func.ReturnType == mappedResultType)
- {
- builder.Return(interopReturnValue);
- }
- else
- {
- var returnValue = builder.BitCast(interopReturnValue, func.ReturnType);
- builder.Return(returnValue);
- }
- }
+ this.GenerateRequiredFunctions();
- ///
- /// Maps a QIR type to a more interop-friendly type using the specified type mapping for interoperability.
- ///
- /// The type to map
- /// The mapped type
- private ITypeRef MapToInteropType(ITypeRef t)
- {
- string typeName = "";
- if (t == this.Types.Result)
- {
- typeName = TypeNames.Result;
- }
- else if (t == this.Types.Array)
- {
- typeName = TypeNames.Array;
- }
- else if (t == this.Types.Pauli)
- {
- typeName = TypeNames.Pauli;
- }
- // we use 32 bit ints in some cases, e.g. for exponents
- else if (t == this.Types.Int || t == this.Context.Int32Type)
- {
- typeName = TypeNames.Int;
- }
- else if (t == this.Types.Double)
- {
- typeName = TypeNames.Double;
- }
- else if (t == this.Types.Bool)
- {
- typeName = TypeNames.Bool;
- }
- else if (t == this.Types.BigInt)
- {
- typeName = TypeNames.BigInt;
- }
- else if (t == this.Types.String)
- {
- typeName = TypeNames.String;
- }
- else if (t == this.Types.Qubit)
- {
- typeName = TypeNames.Qubit;
- }
- else if (t == this.Types.Callable)
- {
- typeName = TypeNames.Callable;
- }
- else if (t == this.Types.Range)
- {
- typeName = TypeNames.Range;
- }
- else if (t == this.Types.Tuple)
+ if (!this.Module.Verify(out string validationErrors))
{
- typeName = TypeNames.Tuple;
+ File.WriteAllText(fileName, $"LLVM errors:{Environment.NewLine}{validationErrors}");
}
- // todo: Currently, e.g. void (this.Context.VoidType) is not covered,
- // and for some reason we end up with i8* here as well. It would be good to cover everything and throw if something is not covered.
- if ((typeName != string.Empty) && this.Config.InteropTypeMapping.TryGetValue(typeName, out string replacementName))
- {
- if (this.interopType.TryGetValue(typeName, out ITypeRef interopType))
- {
- return interopType;
- }
- else
- {
- var newType = this.Context.CreateStructType(replacementName).CreatePointerType();
- this.interopType[typeName] = newType;
- return newType;
- }
- }
- else
+ if (!this.Module.WriteToTextFile(fileName, out string errorMessage))
{
- return t;
+ throw new IOException(errorMessage);
}
}
@@ -802,6 +468,7 @@ internal IrFunction GetOrCreateTargetInstruction(string name) =>
///
/// Tries to find a global Q# callable in the current compilation.
///
+ /// The callable's qualified name
/// The Q# callable, if found
/// true if the callable is found, false if not
internal bool TryGetGlobalCallable(QsQualifiedName fullName, [MaybeNullWhen(false)] out QsCallable callable) =>
@@ -810,7 +477,8 @@ internal bool TryGetGlobalCallable(QsQualifiedName fullName, [MaybeNullWhen(fals
///
/// Tries to find a Q# user-defined type in the current compilation.
///
- /// The Q# UDT< if found
+ /// The UDT's qualified name
+ /// The Q# UDT, if found
/// true if the UDT is found, false if not
internal bool TryGetCustomType(QsQualifiedName fullName, [MaybeNullWhen(false)] out QsCustomType udt) =>
this.globalTypes.TryGetValue(fullName, out udt);
@@ -1203,6 +871,36 @@ internal Constant GetOrCreateCallableMemoryManagementTable(TupleValue? capture)
return table;
}
+ ///
+ /// Sets the current function to the given one and sets the parameter names to the given names.
+ /// Populates the body of the given function by invoking the given action with the function parameters.
+ /// If the current block after the invokation is not terminated, adds a void return.
+ ///
+ internal void GenerateFunction(IrFunction func, string?[] argNames, Action> executeBody)
+ {
+ this.StartFunction();
+ this.CurrentFunction = func;
+ for (var i = 0; i < argNames.Length; ++i)
+ {
+ var name = argNames[i];
+ if (name != null)
+ {
+ this.CurrentFunction.Parameters[i].Name = name;
+ }
+ }
+ this.SetCurrentBlock(this.CurrentFunction.AppendBasicBlock("entry"));
+
+ this.ScopeMgr.OpenScope();
+ executeBody(this.CurrentFunction.Parameters);
+ var isTerminated = this.CurrentBlock?.Terminator != null;
+ this.ScopeMgr.CloseScope(isTerminated);
+ if (!isTerminated)
+ {
+ this.CurrentBuilder.Return();
+ }
+ this.EndFunction();
+ }
+
///
/// Callables within QIR are bundles of four functions. When callables are assigned to variable or
/// passed around, which one of these functions is ultimately invoked is strictly runtime information.
@@ -1288,22 +986,6 @@ Value GenerateBaseMethodCall(QsCallable callable, QsSpecializationKind specKind,
}
}
- void GenerateFunction(IrFunction func, string[] argNames, Action> executeBody)
- {
- this.CurrentFunction = func;
- for (var i = 0; i < argNames.Length; ++i)
- {
- this.CurrentFunction.Parameters[i].Name = argNames[i];
- }
- this.CurrentBlock = this.CurrentFunction.AppendBasicBlock("entry");
- this.CurrentBuilder = new InstructionBuilder(this.CurrentBlock);
-
- this.ScopeMgr.OpenScope();
- executeBody(this.CurrentFunction.Parameters);
- this.ScopeMgr.CloseScope(isTerminated: false);
- this.CurrentBuilder.Return();
- }
-
foreach (var (callable, _) in this.callableTables.Values)
{
foreach (var spec in callable.Specializations)
@@ -1312,7 +994,7 @@ void GenerateFunction(IrFunction func, string[] argNames, Action
+ this.GenerateFunction(func, new[] { "capture-tuple", "arg-tuple", "result-tuple" }, parameters =>
{
var argTuple = GetArgumentTuple(spec.Signature.ArgumentType, parameters[1]);
var args = spec.Signature.ArgumentType.Resolution.IsUserDefinedType
@@ -1331,7 +1013,7 @@ void GenerateFunction(IrFunction func, string[] argNames, Action
+ this.GenerateFunction(func, new[] { "capture-tuple", "count-change" }, parameters =>
{
var capture = GetArgumentTuple(type, parameters[0]);
var countChange = this.Values.FromSimpleValue(parameters[1], ResolvedType.New(ResolvedTypeKind.Int));
@@ -1365,6 +1047,16 @@ void GenerateFunction(IrFunction func, string[] argNames, ActionA range with the given start, step and end.
+ internal IValue CreateRange(Value start, Value step, Value end)
+ {
+ Value constant = this.CurrentBuilder.Load(this.Types.Range, this.Constants.EmptyRange);
+ constant = this.CurrentBuilder.InsertValue(constant, start, 0u);
+ constant = this.CurrentBuilder.InsertValue(constant, step, 1u);
+ constant = this.CurrentBuilder.InsertValue(constant, end, 2u);
+ return this.Values.From(constant, ResolvedType.New(ResolvedTypeKind.Range));
+ }
+
///
/// Creates a for-loop that breaks based on a condition.
///
diff --git a/src/QsCompiler/QirGeneration/Generator.cs b/src/QsCompiler/QirGeneration/Generator.cs
index b34de216bc..c2e784e675 100644
--- a/src/QsCompiler/QirGeneration/Generator.cs
+++ b/src/QsCompiler/QirGeneration/Generator.cs
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
+using Microsoft.Quantum.QIR;
using Microsoft.Quantum.QsCompiler.SyntaxTree;
using Microsoft.Quantum.QsCompiler.Transformations.Core;
@@ -11,11 +12,6 @@ namespace Microsoft.Quantum.QsCompiler.QIR
///
public class Generator : SyntaxTreeTransformation
{
- ///
- /// The configuration used for QIR emission.
- ///
- public readonly Configuration Config;
-
///
/// The compilation unit for which QIR is generated.
///
@@ -39,11 +35,9 @@ public class Generator : SyntaxTreeTransformation
/// Instantiates a transformation capable of emitting QIR for the given compilation.
///
/// The compilation for which to generate QIR
- /// The configuration for the QIR generation
- public Generator(QsCompilation compilation, Configuration config)
- : base(new GenerationContext(compilation.Namespaces, config), TransformationOptions.NoRebuild)
+ public Generator(QsCompilation compilation)
+ : base(new GenerationContext(compilation.Namespaces), TransformationOptions.NoRebuild)
{
- this.Config = config;
this.Compilation = compilation;
this.Namespaces = new QirNamespaceTransformation(this, TransformationOptions.NoRebuild);
@@ -59,7 +53,7 @@ public Generator(QsCompilation compilation, Configuration config)
}
///
- /// Constructs the QIR for the compilation.
+ /// Constructs the QIR for the compilation, including interop-friendly functions for entry points.
/// Does not emit anything; use to output the constructed QIR.
///
public void Apply()
@@ -71,7 +65,8 @@ public void Apply()
foreach (var epName in this.Compilation.EntryPoints)
{
- this.SharedState.GenerateEntryPoint(epName);
+ var wrapperName = GenerationContext.EntryPointName(epName);
+ this.SharedState.CreateInteropWrapper(wrapperName, epName, AttributeNames.EntryPoint);
}
}
diff --git a/src/QsCompiler/QirGeneration/Interop.cs b/src/QsCompiler/QirGeneration/Interop.cs
new file mode 100644
index 0000000000..f2c854cce1
--- /dev/null
+++ b/src/QsCompiler/QirGeneration/Interop.cs
@@ -0,0 +1,500 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Linq;
+using Microsoft.Quantum.QIR;
+using Microsoft.Quantum.QIR.Emission;
+using Microsoft.Quantum.QsCompiler.SyntaxTokens;
+using Microsoft.Quantum.QsCompiler.SyntaxTree;
+using Ubiquity.NET.Llvm.Instructions;
+using Ubiquity.NET.Llvm.Types;
+using Ubiquity.NET.Llvm.Values;
+
+namespace Microsoft.Quantum.QsCompiler.QIR
+{
+ using ArgumentTuple = QsTuple>;
+ using ResolvedTypeKind = QsTypeKind;
+
+ ///
+ /// This class contains utils for facilitating interoperability and entry point handling.
+ ///
+ internal sealed class Interop
+ {
+ private readonly GenerationContext sharedState;
+
+ private Interop(GenerationContext sharedState) =>
+ this.sharedState = sharedState;
+
+ // public static methods calling into private methods
+
+ ///
+ public static IrFunction GenerateWrapper(GenerationContext sharedState, string wrapperName, ArgumentTuple argumentTuple, ResolvedType returnType, IrFunction implementation) =>
+ new Interop(sharedState).GenerateWrapper(wrapperName, argumentTuple, returnType, implementation);
+
+ // private methods
+
+ ///
+ /// Creates a suitable array of values to access the item at a given index for a pointer to a struct.
+ ///
+ private Value[] PointerIndex(int index) => new[]
+ {
+ this.sharedState.Context.CreateConstant(0L),
+ this.sharedState.Context.CreateConstant(index)
+ };
+
+ ///
+ /// Applies the map function to the given items, filters all items that are null,
+ /// and returns the mapped non-null values as array.
+ ///
+ /// The type of the items in the given sequence.
+ /// The type of the items in the returned array.
+ /// The function to apply to each item in the sequence.
+ /// The sequence of items to map.
+ private static TOut[] WithoutNullValues(Func map, IEnumerable items)
+ where TOut : class =>
+ items.Select(map).Where(i => i != null).Select(i => i!).ToArray();
+
+ ///
+ /// Bitcasts the given value to the expected type if needed.
+ /// Does nothing if the native type of the value already matches the expected type.
+ ///
+ private Value CastToType(Value value, ITypeRef expectedType) =>
+ value.NativeType.Equals(expectedType)
+ ? value
+ : this.sharedState.CurrentBuilder.BitCast(value, expectedType);
+
+ ///
+ private ITypeRef? MapToInteropType(ResolvedType type) =>
+ this.MapToInteropType(this.sharedState.LlvmTypeFromQsharpType(type));
+
+ ///
+ /// Maps the given Q#/QIR type to a more interop-friendly type.
+ /// Returns null only if the given type is Unit. Strips items of type Unit inside tuples.
+ ///
+ ///
+ /// The given type is a pointer to a non-struct type,
+ /// or the given type is not specified in the QIR format.
+ ///
+ private ITypeRef? MapToInteropType(ITypeRef t)
+ {
+ // Range, Tuple (typed and untyped), Array, Result, String, BigInt, Callable, and Qubit
+ // are all structs or struct pointers.
+ t = t.IsPointer ? Types.StructFromPointer(t) : t;
+ var typeName = (t as IStructType)?.Name;
+
+ var bytePtrType = this.sharedState.Context.Int8Type.CreatePointerType();
+
+ if (typeName == TypeNames.Array || typeName == TypeNames.BigInt)
+ {
+ return this.sharedState.Context.CreateStructType(
+ packed: false,
+ this.sharedState.Context.Int64Type,
+ this.sharedState.Types.DataArrayPointer)
+ .CreatePointerType();
+ }
+ else if (typeName == TypeNames.String)
+ {
+ return this.sharedState.Types.DataArrayPointer;
+ }
+ else if (typeName == TypeNames.Callable || typeName == TypeNames.Qubit)
+ {
+ return bytePtrType;
+ }
+ else if (typeName == TypeNames.Result)
+ {
+ return this.sharedState.Context.Int8Type;
+ }
+ else if (t is IStructType st)
+ {
+ var itemTypes = WithoutNullValues(this.MapToInteropType, st.Members);
+ return itemTypes.Length > 0
+ ? this.sharedState.Context.CreateStructType(packed: false, itemTypes).CreatePointerType()
+ : null;
+ }
+ if (t.IsInteger)
+ {
+ // covers Int, Bool, Pauli
+ var nrBytes = 1 + ((t.IntegerBitWidth - 1) / 8);
+ return this.sharedState.Context.GetIntType(8 * nrBytes);
+ }
+ else if (t.IsFloatingPoint)
+ {
+ return this.sharedState.Context.DoubleType;
+ }
+ else
+ {
+ throw new ArgumentException("Unrecognized type");
+ }
+ }
+
+ ///
+ /// Assuming the given parameters are defined by flattening the given argument tuple and stripping
+ /// all values of type Unit, constructs the argument(s) to the QIR function that matches the argument tuple.
+ /// The arguments of the current function are assumed to be given as interop friendly types
+ /// defined by .
+ /// This method generates suitable calls to the QIR runtime functions and other necessary
+ /// conversions and casts to construct the arguments for the QIR function;
+ /// i.e. this method implements the mapping "interop-friendly function arguments -> QIR function arguments".
+ ///
+ /// The array of arguments with which to invoke the QIR function with the given argument tuple.
+ /// The current function is null.
+ private Value[] ProcessArguments(ArgumentTuple arg, IReadOnlyList parameters)
+ {
+ if (this.sharedState.CurrentFunction == null)
+ {
+ throw new InvalidOperationException("the current function is null");
+ }
+
+ (Value Length, Value DataArray) LoadSizedArray(Value value)
+ {
+ var lengthPtr = this.sharedState.CurrentBuilder.GetElementPtr(Types.PointerElementType(value), value, this.PointerIndex(0));
+ var dataArrPtr = this.sharedState.CurrentBuilder.GetElementPtr(Types.PointerElementType(value), value, this.PointerIndex(1));
+ var length = this.sharedState.CurrentBuilder.Load(this.sharedState.Types.Int, lengthPtr);
+ var dataArr = this.sharedState.CurrentBuilder.Load(this.sharedState.Types.DataArrayPointer, dataArrPtr);
+ return (length, dataArr);
+ }
+
+ IValue[] GetStructItems(Value value, IEnumerable itemTypes)
+ {
+ var itemIndex = 0;
+ Value NextTupleItem()
+ {
+ var itemPtr = this.sharedState.CurrentBuilder.GetElementPtr(Types.PointerElementType(value), value, this.PointerIndex(itemIndex++));
+ return this.sharedState.CurrentBuilder.Load(Types.PointerElementType(itemPtr), itemPtr);
+ }
+ return itemTypes.Select(arg => ProcessGivenValue(arg, NextTupleItem)).ToArray();
+ }
+
+ IValue ProcessGivenValue(ResolvedType type, Func next)
+ {
+ if (type.Resolution.IsUnitType)
+ {
+ return this.sharedState.Values.Unit;
+ }
+
+ Value givenValue = next();
+ if (type.Resolution is ResolvedTypeKind.ArrayType arrItemType)
+ {
+ var (length, dataArr) = LoadSizedArray(givenValue);
+ ArrayValue array = this.sharedState.Values.CreateArray(length, arrItemType.Item);
+
+ var dataArrStart = this.sharedState.CurrentBuilder.PointerToInt(dataArr, this.sharedState.Context.Int64Type);
+ var givenArrElementType = this.MapToInteropType(array.LlvmElementType) ?? this.sharedState.Values.Unit.LlvmType;
+ var givenArrElementSize = this.sharedState.ComputeSizeForType(givenArrElementType);
+
+ void PopulateItem(Value index)
+ {
+ var element = ProcessGivenValue(array.QSharpElementType, () =>
+ {
+ var offset = this.sharedState.CurrentBuilder.Mul(index, givenArrElementSize);
+ var elementPointer = this.sharedState.CurrentBuilder.IntToPointer(
+ this.sharedState.CurrentBuilder.Add(dataArrStart, offset),
+ givenArrElementType.CreatePointerType());
+ return this.sharedState.CurrentBuilder.Load(givenArrElementType, elementPointer);
+ });
+ array.GetArrayElementPointer(index).StoreValue(element);
+ }
+
+ var start = this.sharedState.Context.CreateConstant(0L);
+ var end = this.sharedState.CurrentBuilder.Sub(array.Length, this.sharedState.Context.CreateConstant(1L));
+ this.sharedState.IterateThroughRange(start, null, end, PopulateItem);
+ return array;
+ }
+ else if (type.Resolution is ResolvedTypeKind.TupleType items)
+ {
+ var tupleItems = GetStructItems(givenValue, items.Item);
+ return this.sharedState.Values.CreateTuple(tupleItems);
+ }
+ else if (type.Resolution.IsBigInt)
+ {
+ var createBigInt = this.sharedState.GetOrCreateRuntimeFunction(RuntimeLibrary.BigIntCreateArray);
+ var (length, dataArr) = LoadSizedArray(givenValue);
+ var argValue = this.sharedState.CurrentBuilder.Call(createBigInt, length, dataArr);
+ var value = this.sharedState.Values.From(argValue, type);
+ this.sharedState.ScopeMgr.RegisterValue(value);
+ return value;
+ }
+ else if (type.Resolution.IsString)
+ {
+ var createString = this.sharedState.GetOrCreateRuntimeFunction(RuntimeLibrary.StringCreate);
+ var argValue = this.sharedState.CurrentBuilder.Call(createString, this.sharedState.Context.CreateConstant(0), givenValue);
+ var value = this.sharedState.Values.From(argValue, type);
+ this.sharedState.ScopeMgr.RegisterValue(value);
+ return value;
+ }
+ else if (type.Resolution.IsResult)
+ {
+ var zero = this.sharedState.CurrentBuilder.Load(this.sharedState.Types.Result, this.sharedState.Constants.ResultZero);
+ var one = this.sharedState.CurrentBuilder.Load(this.sharedState.Types.Result, this.sharedState.Constants.ResultOne);
+ var cond = this.sharedState.CurrentBuilder.Compare(
+ IntPredicate.Equal,
+ givenValue,
+ this.sharedState.Context.CreateConstant(givenValue.NativeType, 0u, false));
+ var argValue = this.sharedState.CurrentBuilder.Select(cond, zero, one);
+ return this.sharedState.Values.From(argValue, type);
+ }
+ else if (type.Resolution.IsRange)
+ {
+ var itemTypes = Enumerable.Repeat(ResolvedType.New(ResolvedTypeKind.Int), 3);
+ var rangeItems = GetStructItems(givenValue, itemTypes);
+ return this.sharedState.CreateRange(rangeItems[0].Value, rangeItems[1].Value, rangeItems[2].Value);
+ }
+ else if (givenValue.NativeType.IsInteger)
+ {
+ var expectedType = this.sharedState.LlvmTypeFromQsharpType(type);
+ var argValue = this.sharedState.CurrentBuilder.IntCast(givenValue, expectedType, type.Resolution.IsInt);
+ return this.sharedState.Values.FromSimpleValue(argValue, type);
+ }
+ else if (givenValue.NativeType.IsFloatingPoint)
+ {
+ return this.sharedState.Values.FromSimpleValue(givenValue, type);
+ }
+ else
+ {
+ // bitcast to the correct type and return
+ var expectedArgType = this.sharedState.LlvmTypeFromQsharpType(type);
+ var argValue = this.CastToType(givenValue, expectedArgType);
+ return this.sharedState.Values.From(argValue, type);
+ }
+ }
+
+ IValue ProcessArgumentTupleItem(ArgumentTuple item, Func nextArgument)
+ {
+ if (item is ArgumentTuple.QsTuple innerTuple)
+ {
+ var tupleItems = innerTuple.Item.Select(arg => ProcessArgumentTupleItem(arg, nextArgument)).ToArray();
+ return this.sharedState.Values.CreateTuple(tupleItems);
+ }
+ else
+ {
+ return item is ArgumentTuple.QsTupleItem innerItem
+ ? ProcessGivenValue(innerItem.Item.Type, nextArgument)
+ : throw new NotSupportedException("unknown item in argument tuple");
+ }
+ }
+
+ var currentFunctionArgIndex = 0;
+ Value NextArgument() => parameters[currentFunctionArgIndex++];
+ var args = arg is ArgumentTuple.QsTuple argTuple ? argTuple.Item : ImmutableArray.Create(arg);
+ return args.Select(item => ProcessArgumentTupleItem(item, NextArgument).Value).ToArray();
+ }
+
+ ///
+ /// This method generates suitable calls, conversions and casts to map the given return value
+ /// of a QIR function to an interop-friendly value; i.e. this method implements the mapping
+ /// "QIR value -> interop friendly value". It strips all inner tuple items of type Unit,
+ /// and returns null only if the given value represents a value of type Unit.
+ ///
+ /// The memory for the returned value is allocated on the heap using the corresponding runtime
+ /// function and will not be freed by the QIR runtime.
+ /// It is the responsibility of the code calling into the QIR entry point wrapper to free that memory.
+ ///
+ /// The interop-friendly value for the given value obtained by invoking a QIR function.
+ /// The current function is null.
+ private Value? ProcessReturnValue(IValue res)
+ {
+ if (this.sharedState.CurrentFunction == null)
+ {
+ throw new InvalidOperationException("the current function is null");
+ }
+
+ Value CopyToMemory(IPointerType targetType, Value size, Value? sourcePtr = null)
+ {
+ var malloc = this.sharedState.GetOrCreateRuntimeFunction(RuntimeLibrary.HeapAllocate);
+ var allocated = this.sharedState.CurrentBuilder.Call(malloc, size);
+ if (sourcePtr != null)
+ {
+ this.sharedState.CurrentBuilder.MemCpy(allocated, sourcePtr, size, false);
+ }
+ return this.sharedState.CurrentBuilder.BitCast(allocated, targetType);
+ }
+
+ Value PopulateStruct(IPointerType mappedType, Value[] tupleItems)
+ {
+ var mappedStructType = Types.StructFromPointer(mappedType);
+ var size = this.sharedState.ComputeSizeForType(mappedStructType);
+ var mappedTuple = CopyToMemory(mappedType, size);
+
+ for (var itemIdx = 0; itemIdx < mappedStructType.Members.Count; ++itemIdx)
+ {
+ var itemPtr = this.sharedState.CurrentBuilder.GetElementPtr(mappedStructType, mappedTuple, this.PointerIndex(itemIdx));
+ var tupleItem = this.CastToType(tupleItems[itemIdx], mappedStructType.Members[itemIdx]);
+ this.sharedState.CurrentBuilder.Store(tupleItem, itemPtr);
+ }
+ return mappedTuple;
+ }
+
+ if (res.QSharpType.Resolution.IsUnitType)
+ {
+ return null;
+ }
+
+ if (res is ArrayValue array)
+ {
+ var malloc = this.sharedState.GetOrCreateRuntimeFunction(RuntimeLibrary.HeapAllocate);
+ var dataArrElementType = this.MapToInteropType(array.QSharpElementType) ?? this.sharedState.Values.Unit.LlvmType;
+ var sizePerElement = this.sharedState.ComputeSizeForType(dataArrElementType);
+ var dataArr = this.sharedState.CurrentBuilder.Call(malloc, this.sharedState.CurrentBuilder.Mul(array.Length, sizePerElement));
+
+ var dataArrStart = this.sharedState.CurrentBuilder.PointerToInt(dataArr, this.sharedState.Context.Int64Type);
+ void PopulateItem(Value index)
+ {
+ var offset = this.sharedState.CurrentBuilder.Mul(index, sizePerElement);
+ var elementPointer = this.sharedState.CurrentBuilder.IntToPointer(
+ this.sharedState.CurrentBuilder.Add(dataArrStart, offset),
+ dataArrElementType.CreatePointerType());
+ var element = this.ProcessReturnValue(array.GetArrayElement(index)) ?? this.sharedState.Values.Unit.Value;
+ this.sharedState.CurrentBuilder.Store(element, elementPointer);
+ }
+
+ var start = this.sharedState.Context.CreateConstant(0L);
+ var end = this.sharedState.CurrentBuilder.Sub(array.Length, this.sharedState.Context.CreateConstant(1L));
+ this.sharedState.IterateThroughRange(start, null, end, PopulateItem);
+
+ var tupleItems = new[] { array.Length, dataArr }; // FIXME: CAST DATA ARR TO THE RIGHT TYPE IF NEEDED
+ var mappedType = this.MapToInteropType(array.QSharpType)!;
+ return PopulateStruct((IPointerType)mappedType, tupleItems);
+ }
+ else if (res is TupleValue tuple)
+ {
+ var mappedType = this.MapToInteropType(tuple.QSharpType);
+ if (mappedType == null)
+ {
+ return null;
+ }
+ else if (tuple.LlvmType.Equals(mappedType))
+ {
+ var size = this.sharedState.ComputeSizeForType(tuple.StructType);
+ return CopyToMemory((IPointerType)mappedType, size, tuple.TypedPointer);
+ }
+
+ var tupleItems = WithoutNullValues(this.ProcessReturnValue, tuple.GetTupleElements());
+ return PopulateStruct((IPointerType)mappedType, tupleItems);
+ }
+ else if (res.QSharpType.Resolution.IsBigInt)
+ {
+ // TODO: We can't know the length of the big int without runtime support.
+ // We may also need functions to access the data array for both string and big int.
+ throw new NotImplementedException("returning values of type BigInt is not yet supported");
+ }
+ else if (res.QSharpType.Resolution.IsString)
+ {
+ var getLength = this.sharedState.GetOrCreateRuntimeFunction(RuntimeLibrary.StringGetLength);
+ var strLength = this.sharedState.CurrentBuilder.Call(getLength, res.Value);
+ var size = this.sharedState.CurrentBuilder.IntCast(strLength, this.sharedState.Context.Int64Type, true);
+
+ var getData = this.sharedState.GetOrCreateRuntimeFunction(RuntimeLibrary.StringGetData);
+ var strData = this.sharedState.CurrentBuilder.Call(getData, res.Value);
+
+ var expectedType = this.MapToInteropType(res.LlvmType)!;
+ return CopyToMemory((IPointerType)expectedType, size, strData); // not sure if it is better to avoid the copy and increase the ref count
+ }
+ else if (res.QSharpType.Resolution.IsResult)
+ {
+ var zero = this.sharedState.CurrentBuilder.Load(this.sharedState.Types.Result, this.sharedState.Constants.ResultZero);
+ var resType = this.MapToInteropType(this.sharedState.Types.Result)!;
+ var zeroValue = this.sharedState.Context.CreateConstant(resType, 0u, false);
+ var oneValue = this.sharedState.Context.CreateConstant(resType, ~0u, false);
+
+ var equals = this.sharedState.GetOrCreateRuntimeFunction(RuntimeLibrary.ResultEqual);
+ var cond = this.sharedState.CurrentBuilder.Call(equals, res.Value, zero);
+ return this.sharedState.CurrentBuilder.Select(cond, zeroValue, oneValue);
+ }
+ else if (res.QSharpType.Resolution.IsRange)
+ {
+ var start = this.sharedState.CurrentBuilder.ExtractValue(res.Value, 0u);
+ var step = this.sharedState.CurrentBuilder.ExtractValue(res.Value, 1u);
+ var end = this.sharedState.CurrentBuilder.ExtractValue(res.Value, 2u);
+
+ var expectedType = this.MapToInteropType(res.LlvmType)!;
+ return PopulateStruct((IPointerType)expectedType, new[] { start, step, end });
+ }
+ else if (res.LlvmType.IsInteger)
+ {
+ var expectedType = this.MapToInteropType(res.LlvmType)!;
+ return this.sharedState.CurrentBuilder.IntCast(res.Value, expectedType, res.QSharpType.Resolution.IsInt);
+ }
+ else if (res.LlvmType.IsFloatingPoint)
+ {
+ return res.Value;
+ }
+ else
+ {
+ // callables and qubits
+ var expectedType = this.MapToInteropType(res.LlvmType)!;
+ this.sharedState.ScopeMgr.IncreaseReferenceCount(res);
+ return this.CastToType(res.Value, expectedType);
+ }
+ }
+
+ ///
+ /// Generates an interop-friendly wrapper around a QIR function that can be invoked from within
+ /// native code without relying on the QIR runtime or adhering to the QIR specification.
+ /// See and
+ /// for more detail.
+ ///
+ /// Creates an alias with the given name instead of a wrapper function
+ /// if the wrapper signature and signature of the QIR implementation match.
+ ///
+ /// The function name to give the wrapper.
+ /// The argument tuple of the callable that the wrapper should invoke.
+ /// The return type of the callable that the wrapper should invoke.
+ /// The QIR function that implements the body of the function that should be invoked.
+ /// The created wrapper function or the implementation if no wrapper function has been created.
+ /// No callable with the given name exists in the compilation.
+ private IrFunction GenerateWrapper(string wrapperName, ArgumentTuple argumentTuple, ResolvedType returnType, IrFunction implementation)
+ {
+ var argItems = SyntaxGenerator.ExtractItems(argumentTuple)
+ .Where(sym => !sym.Type.Resolution.IsUnitType)
+ .ToArray();
+
+ ITypeRef[] wrapperArgsTypes = argItems
+ .Select(sym => this.MapToInteropType(sym.Type)!)
+ .ToArray();
+ var wrapperReturnType = this.MapToInteropType(returnType);
+ var wrapperSignature = this.sharedState.Context.GetFunctionType(
+ wrapperReturnType ?? this.sharedState.Context.VoidType,
+ wrapperArgsTypes);
+
+ if (wrapperSignature.Equals(implementation.Signature))
+ {
+ this.sharedState.Module.AddAlias(implementation, wrapperName).Linkage = Linkage.External;
+ return implementation;
+ }
+ else
+ {
+ var wrapperFunc = this.sharedState.Module.CreateFunction(wrapperName, wrapperSignature);
+ var argNames = argItems.Select(arg => arg.VariableName is QsLocalSymbol.ValidName name ? name.Item : null).ToArray();
+
+ this.sharedState.GenerateFunction(wrapperFunc, argNames, parameters =>
+ {
+ var argValueList = this.ProcessArguments(argumentTuple, parameters);
+ var evaluatedValue = this.sharedState.CurrentBuilder.Call(implementation, argValueList);
+ var result = this.sharedState.Values.From(evaluatedValue, returnType);
+ this.sharedState.ScopeMgr.RegisterValue(result);
+
+ if (wrapperSignature.ReturnType.IsVoid)
+ {
+ this.sharedState.AddReturn(this.sharedState.Values.Unit, true);
+ }
+ else if (wrapperSignature.ReturnType.Equals(result.LlvmType))
+ {
+ this.sharedState.AddReturn(result, false);
+ }
+ else
+ {
+ // ProcessReturnValue makes sure the memory for the returned value isn't freed
+ var returnValue = this.ProcessReturnValue(result)!;
+ this.sharedState.ScopeMgr.ExitFunction(this.sharedState.Values.Unit);
+ this.sharedState.CurrentBuilder.Return(returnValue);
+ }
+ });
+
+ return wrapperFunc;
+ }
+ }
+ }
+}
diff --git a/src/QsCompiler/QirGeneration/QIR/DataStructures.cs b/src/QsCompiler/QirGeneration/QIR/DataStructures.cs
index be167cb382..b837a8df3d 100644
--- a/src/QsCompiler/QirGeneration/QIR/DataStructures.cs
+++ b/src/QsCompiler/QirGeneration/QIR/DataStructures.cs
@@ -281,7 +281,7 @@ internal TupleValue(ImmutableArray elementTypes, GenerationContext
internal TupleValue(UserDefinedType? type, Value tuple, ImmutableArray elementTypes, GenerationContext context)
{
var isTypedTuple = Types.IsTypedTuple(tuple.NativeType);
- var isOpaqueTuple = Types.IsTuple(tuple.NativeType);
+ var isOpaqueTuple = !tuple.IsNull && Types.IsTupleOrUnit(tuple.NativeType);
if (!isTypedTuple && !isOpaqueTuple)
{
throw new ArgumentException("expecting either an opaque or a typed tuple");
diff --git a/src/QsCompiler/QirGeneration/QIR/Functions.cs b/src/QsCompiler/QirGeneration/QIR/Functions.cs
index 7746250852..09e35dd000 100644
--- a/src/QsCompiler/QirGeneration/QIR/Functions.cs
+++ b/src/QsCompiler/QirGeneration/QIR/Functions.cs
@@ -67,7 +67,7 @@ public Functions(GenerationContext sharedState)
/// The mangled names are a double underscore, "quantum", and another double underscore, followed by
/// "rt" or "qis", another double underscore, and then the base name.
///
- /// The component that is expected to provide the function
+ /// The component that is expected to provide the function
/// The name of the function without the component prefix
/// The mangled function name
/// No naming convention is defined for the given component.
@@ -80,7 +80,6 @@ public Functions(GenerationContext sharedState)
// public and internal methods
- /// The generation context in which to emit the instructions
/// The range expression for which to create the access functions
///
/// Three functions to access the start, step, and end of a range.
@@ -112,9 +111,9 @@ public Functions(GenerationContext sharedState)
else
{
var range = this.sharedState.EvaluateSubexpression(rangeEx).Value;
- startValue = () => this.sharedState.CurrentBuilder.ExtractValue(range, 0);
- stepValue = () => this.sharedState.CurrentBuilder.ExtractValue(range, 1);
- endValue = () => this.sharedState.CurrentBuilder.ExtractValue(range, 2);
+ startValue = () => this.sharedState.CurrentBuilder.ExtractValue(range, 0u);
+ stepValue = () => this.sharedState.CurrentBuilder.ExtractValue(range, 1u);
+ endValue = () => this.sharedState.CurrentBuilder.ExtractValue(range, 2u);
}
return (startValue, stepValue, endValue);
}
@@ -202,13 +201,7 @@ private IValue RangeReverse(TypedExpression arg)
step,
this.sharedState.CurrentBuilder.SDiv(
this.sharedState.CurrentBuilder.Sub(end, start), step)));
- Value reversed = this.sharedState.CurrentBuilder.Load(
- this.sharedState.Types.Range,
- this.sharedState.Constants.EmptyRange);
- reversed = this.sharedState.CurrentBuilder.InsertValue(reversed, newStart, 0u);
- reversed = this.sharedState.CurrentBuilder.InsertValue(reversed, this.sharedState.CurrentBuilder.Neg(step), 1u);
- reversed = this.sharedState.CurrentBuilder.InsertValue(reversed, start, 2u);
- return this.sharedState.Values.From(reversed, Range);
+ return this.sharedState.CreateRange(newStart, this.sharedState.CurrentBuilder.Neg(step), start);
}
}
}
diff --git a/src/QsCompiler/QirGeneration/QIR/RuntimeLibrary.cs b/src/QsCompiler/QirGeneration/QIR/RuntimeLibrary.cs
index 0c5d4d2216..e2e97001c6 100644
--- a/src/QsCompiler/QirGeneration/QIR/RuntimeLibrary.cs
+++ b/src/QsCompiler/QirGeneration/QIR/RuntimeLibrary.cs
@@ -8,8 +8,8 @@ namespace Microsoft.Quantum.QIR
///
public static class RuntimeLibrary
{
- // int functions
- public const string IntPower = "int_power";
+ // Q# specific helpers
+ internal const string HeapAllocate = "heap_alloc";
// result functions
public const string ResultUpdateReferenceCount = "result_update_reference_count";
@@ -17,6 +17,8 @@ public static class RuntimeLibrary
// string functions
public const string StringCreate = "string_create";
+ public const string StringGetData = "string_get_data";
+ public const string StringGetLength = "string_get_length";
public const string StringUpdateReferenceCount = "string_update_reference_count";
public const string StringConcatenate = "string_concatenate";
public const string StringEqual = "string_equal";
@@ -59,15 +61,12 @@ public static class RuntimeLibrary
public const string TupleCopy = "tuple_copy";
// array functions
- public const string ArrayCreate = "array_create";
- public const string ArrayGetElementPtr = "array_get_element_ptr";
public const string ArrayCreate1d = "array_create_1d";
public const string ArrayGetElementPtr1d = "array_get_element_ptr_1d";
public const string ArrayUpdateAliasCount = "array_update_alias_count";
public const string ArrayUpdateReferenceCount = "array_update_reference_count";
public const string ArrayCopy = "array_copy";
public const string ArrayConcatenate = "array_concatenate";
- public const string ArraySlice = "array_slice";
public const string ArraySlice1d = "array_slice_1d";
public const string ArrayGetSize1d = "array_get_size_1d";
diff --git a/src/QsCompiler/QirGeneration/QIR/Types.cs b/src/QsCompiler/QirGeneration/QIR/Types.cs
index 2a464d541f..541e1d981c 100644
--- a/src/QsCompiler/QirGeneration/QIR/Types.cs
+++ b/src/QsCompiler/QirGeneration/QIR/Types.cs
@@ -137,13 +137,6 @@ internal Types(Context context)
// internal helpers to simplify common code
- ///
- /// Type by which data allocated as global constant array is passed to the runtime.
- /// String and big integers for example are instantiated with a data array.
- ///
- internal IPointerType DataArrayPointer =>
- this.context.Int8Type.CreatePointerType();
-
///
/// Given the type of a pointer to a struct, returns the type of the struct.
/// This method thus is the inverse mapping of CreatePointerType.
@@ -161,6 +154,13 @@ internal static IStructType StructFromPointer(ITypeRef pointer) =>
internal static ITypeRef PointerElementType(Value pointer) =>
((IPointerType)pointer.NativeType).ElementType;
+ ///
+ /// Type by which data allocated as global constant array is passed to the runtime.
+ /// String and big integers for example are instantiated with a data array.
+ ///
+ internal IPointerType DataArrayPointer =>
+ this.context.Int8Type.CreatePointerType();
+
// public members
///
@@ -193,7 +193,7 @@ t is IPointerType pt
///
/// Determines whether an LLVM type is a pointer to an opaque tuple.
///
- public static bool IsTuple(ITypeRef t) =>
+ public static bool IsTupleOrUnit(ITypeRef t) =>
t is IPointerType pt
&& pt.ElementType is IStructType st
&& st.Name == TypeNames.Tuple;
@@ -245,6 +245,13 @@ public static bool IsString(ITypeRef t) =>
t is IPointerType pt
&& pt.ElementType is IStructType st
&& st.Name == TypeNames.String;
+
+ ///
+ /// Determines whether an LLVM type is a struct type representing a range of integers.
+ ///
+ public static bool IsRange(ITypeRef t) =>
+ t is IStructType st
+ && st.Name == TypeNames.Range;
}
///
diff --git a/src/QsCompiler/QirGeneration/Subtransformations/ExpressionKindTransformation.cs b/src/QsCompiler/QirGeneration/Subtransformations/ExpressionKindTransformation.cs
index cb930bc4d2..f50f8551ee 100644
--- a/src/QsCompiler/QirGeneration/Subtransformations/ExpressionKindTransformation.cs
+++ b/src/QsCompiler/QirGeneration/Subtransformations/ExpressionKindTransformation.cs
@@ -1548,10 +1548,8 @@ IValue DefaultValue(ResolvedType type)
}
else if (type.Resolution.IsString)
{
- var value = this.SharedState.CurrentBuilder.Call(
- this.SharedState.GetOrCreateRuntimeFunction(RuntimeLibrary.StringCreate),
- this.SharedState.Context.CreateConstant(0),
- this.SharedState.Types.DataArrayPointer.GetNullValue());
+ var create = this.SharedState.GetOrCreateRuntimeFunction(RuntimeLibrary.StringCreate);
+ var value = this.SharedState.CurrentBuilder.Call(create, this.SharedState.Context.CreateConstant(0), this.SharedState.Types.DataArrayPointer.GetNullValue());
var built = this.SharedState.Values.From(value, type);
this.SharedState.ScopeMgr.RegisterValue(built);
return built;
@@ -1876,15 +1874,7 @@ public override ResolvedExpressionKind OnRangeLiteral(TypedExpression lhs, Typed
break;
}
Value end = this.SharedState.EvaluateSubexpression(rhs).Value;
-
- Value rangePtr = this.SharedState.Constants.EmptyRange;
- Value constant = this.SharedState.CurrentBuilder.Load(this.SharedState.Types.Range, rangePtr);
- constant = this.SharedState.CurrentBuilder.InsertValue(constant, start, 0);
- constant = this.SharedState.CurrentBuilder.InsertValue(constant, step, 1);
- constant = this.SharedState.CurrentBuilder.InsertValue(constant, end, 2);
-
- var exType = this.SharedState.CurrentExpressionType();
- var value = this.SharedState.Values.From(constant, exType);
+ var value = this.SharedState.CreateRange(start, step, end);
this.SharedState.ValueStack.Push(value);
return ResolvedExpressionKind.InvalidExpr;
@@ -1980,9 +1970,8 @@ Value CreateConstantString(string s)
constantArray,
this.SharedState.Types.DataArrayPointer);
- var n = this.SharedState.Context.CreateConstant(cleanStr.Length);
var createString = this.SharedState.GetOrCreateRuntimeFunction(RuntimeLibrary.StringCreate);
- return this.SharedState.CurrentBuilder.Call(createString, n, zeroLengthString);
+ return this.SharedState.CurrentBuilder.Call(createString, this.SharedState.Context.CreateConstant(0), zeroLengthString);
}
// Creates a string value that needs to be queued for unreferencing.
diff --git a/src/QsCompiler/QirGeneration/Subtransformations/StatementKindTransformation.cs b/src/QsCompiler/QirGeneration/Subtransformations/StatementKindTransformation.cs
index 2adefacb88..173c8fc4cd 100644
--- a/src/QsCompiler/QirGeneration/Subtransformations/StatementKindTransformation.cs
+++ b/src/QsCompiler/QirGeneration/Subtransformations/StatementKindTransformation.cs
@@ -65,8 +65,8 @@ private void CreateVariable(string varName, IValue value, bool mutable = false)
/// to a Value.
///
/// The symbols to bind
- /// The action to invoke to bind each symbol
///
+ /// The action to invoke to bind each symbol
/// The Q# expression that defines the value to bind the symbols to; it will be deconstructed if necessary
///
private void BindSymbolTuple(SymbolTuple symbols, TypedExpression ex, Action bindVariable)
diff --git a/examples/QIR/QirCore.qs b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/QirCore.qs
similarity index 99%
rename from examples/QIR/QirCore.qs
rename to src/QsCompiler/Tests.Compiler/TestCases/QirTests/QirCore.qs
index de169cab59..e63359e95a 100644
--- a/examples/QIR/QirCore.qs
+++ b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/QirCore.qs
@@ -27,4 +27,4 @@ namespace Microsoft.Quantum.Targeting {
@Attribute()
newtype TargetInstruction = String;
-}
\ No newline at end of file
+}
diff --git a/examples/QIR/QirTarget.qs b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/QirTarget.qs
similarity index 97%
rename from examples/QIR/QirTarget.qs
rename to src/QsCompiler/Tests.Compiler/TestCases/QirTests/QirTarget.qs
index fb2add8c10..70fb2da71c 100644
--- a/examples/QIR/QirTarget.qs
+++ b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/QirTarget.qs
@@ -1,4 +1,4 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
+// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Instructions {
@@ -132,4 +132,4 @@ namespace Microsoft.Quantum.Intrinsic {
CNOT(ctls[0], qb);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestArrayUpdate1.ll b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestArrayUpdate1.ll
index 724c09ea64..aa28f0a8d6 100644
--- a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestArrayUpdate1.ll
+++ b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestArrayUpdate1.ll
@@ -56,7 +56,7 @@ body__3: ; preds = %header__3
br i1 %15, label %condTrue__1, label %condFalse__1
condTrue__1: ; preds = %body__3
- %16 = call %String* @__quantum__rt__string_create(i32 3, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @0, i32 0, i32 0))
+ %16 = call %String* @__quantum__rt__string_create(i32 0, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @0, i32 0, i32 0))
br label %condContinue__1
condFalse__1: ; preds = %body__3
diff --git a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestArrayUpdate2.ll b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestArrayUpdate2.ll
index 48fa43f5c2..485c22fc10 100644
--- a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestArrayUpdate2.ll
+++ b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestArrayUpdate2.ll
@@ -39,7 +39,7 @@ body__2: ; preds = %header__2
br i1 %10, label %condTrue__1, label %condFalse__1
condTrue__1: ; preds = %body__2
- %11 = call %String* @__quantum__rt__string_create(i32 3, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @1, i32 0, i32 0))
+ %11 = call %String* @__quantum__rt__string_create(i32 0, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @1, i32 0, i32 0))
br label %condContinue__1
condFalse__1: ; preds = %body__2
diff --git a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestArrayUpdate3.ll b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestArrayUpdate3.ll
index d5fe597606..4f6f36c5ce 100644
--- a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestArrayUpdate3.ll
+++ b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestArrayUpdate3.ll
@@ -48,7 +48,7 @@ condContinue__1: ; preds = %condFalse__1, %exit
call void @__quantum__rt__array_update_alias_count(%Array* %8, i64 -1)
%13 = call %Array* @__quantum__rt__array_copy(%Array* %8, i1 false)
%14 = icmp ne %Array* %8, %13
- %15 = call %String* @__quantum__rt__string_create(i32 5, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @2, i32 0, i32 0))
+ %15 = call %String* @__quantum__rt__string_create(i32 0, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @2, i32 0, i32 0))
%16 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %13, i64 1)
%17 = bitcast i8* %16 to %String**
call void @__quantum__rt__string_update_reference_count(%String* %15, i64 1)
diff --git a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestArrayUpdate4.ll b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestArrayUpdate4.ll
index a6b4a23fbf..ef81ad3c86 100644
--- a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestArrayUpdate4.ll
+++ b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestArrayUpdate4.ll
@@ -1,7 +1,7 @@
define %Array* @Microsoft__Quantum__Testing__QIR__TestArrayUpdate4__body(%Array* %array) {
entry:
call void @__quantum__rt__array_update_alias_count(%Array* %array, i64 1)
- %item = call %String* @__quantum__rt__string_create(i32 5, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @3, i32 0, i32 0))
+ %item = call %String* @__quantum__rt__string_create(i32 0, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @3, i32 0, i32 0))
%0 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 0)
%arr = alloca %Array*, align 8
store %Array* %0, %Array** %arr, align 8
diff --git a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestConditional2.ll b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestConditional2.ll
index 81d8f09743..984c79cbef 100644
--- a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestConditional2.ll
+++ b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestConditional2.ll
@@ -7,8 +7,8 @@ entry:
%3 = bitcast i8* %2 to %String**
%4 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %arr, i64 2)
%5 = bitcast i8* %4 to %String**
- %6 = call %String* @__quantum__rt__string_create(i32 5, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @0, i32 0, i32 0))
- %7 = call %String* @__quantum__rt__string_create(i32 5, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @1, i32 0, i32 0))
+ %6 = call %String* @__quantum__rt__string_create(i32 0, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @0, i32 0, i32 0))
+ %7 = call %String* @__quantum__rt__string_create(i32 0, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @1, i32 0, i32 0))
%8 = call %String* @__quantum__rt__string_create(i32 0, i8* null)
store %String* %6, %String** %1, align 8
store %String* %7, %String** %3, align 8
@@ -22,7 +22,7 @@ condTrue__1: ; preds = %entry
condFalse__1: ; preds = %entry
%9 = call %Array* @__quantum__rt__array_copy(%Array* %arr, i1 false)
%10 = icmp ne %Array* %arr, %9
- %11 = call %String* @__quantum__rt__string_create(i32 1, i8* getelementptr inbounds ([2 x i8], [2 x i8]* @2, i32 0, i32 0))
+ %11 = call %String* @__quantum__rt__string_create(i32 0, i8* getelementptr inbounds ([2 x i8], [2 x i8]* @2, i32 0, i32 0))
%12 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %9, i64 2)
%13 = bitcast i8* %12 to %String**
br i1 %10, label %condContinue__2, label %condFalse__2
diff --git a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestEntryPoint.ll b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestEntryPoint.ll
index 3643e4627d..30823f5e8c 100644
--- a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestEntryPoint.ll
+++ b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestEntryPoint.ll
@@ -1,38 +1,153 @@
-define double @Microsoft__Quantum__Testing__QIR__TestEntryPoint(i64 %a__count, double* %a, i1 %b) #0 {
+define { { i64, i8* }*, i8*, i8, { i64, i64, i64 }*, { i64, i8 }* }* @Microsoft__Quantum__Testing__QIR__TestEntryPoint({ i64, i8* }* %arr, i8* %str, i8 %res, { i64, i64, i64 }* %range, i64 %cnt, i8 %b) #0 {
entry:
- %0 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 %a__count)
- %1 = icmp sgt i64 %a__count, 0
- br i1 %1, label %copy, label %next
-
-copy: ; preds = %entry
- %2 = ptrtoint double* %a to i64
- %3 = sub i64 %a__count, 1
+ %0 = getelementptr { i64, i8* }, { i64, i8* }* %arr, i64 0, i32 0
+ %1 = getelementptr { i64, i8* }, { i64, i8* }* %arr, i64 0, i32 1
+ %2 = load i64, i64* %0, align 4
+ %3 = load i8*, i8** %1, align 8
+ %4 = call %Array* @__quantum__rt__array_create_1d(i32 1, i64 %2)
+ %5 = ptrtoint i8* %3 to i64
+ %6 = sub i64 %2, 1
br label %header__1
-next: ; preds = %exit__1, %entry
- %4 = call double @Microsoft__Quantum__Testing__QIR__TestEntryPoint__body(%Array* %0, i1 %b)
- call void @__quantum__rt__array_update_reference_count(%Array* %0, i64 -1)
- ret double %4
-
-header__1: ; preds = %exiting__1, %copy
- %5 = phi i64 [ 0, %copy ], [ %13, %exiting__1 ]
- %6 = icmp sle i64 %5, %3
- br i1 %6, label %body__1, label %exit__1
+header__1: ; preds = %exiting__1, %entry
+ %7 = phi i64 [ 0, %entry ], [ %16, %exiting__1 ]
+ %8 = icmp sle i64 %7, %6
+ br i1 %8, label %body__1, label %exit__1
body__1: ; preds = %header__1
- %7 = mul i64 %5, 8
- %8 = add i64 %2, %7
- %9 = inttoptr i64 %8 to double*
- %10 = load double, double* %9, align 8
- %11 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %0, i64 %5)
- %12 = bitcast i8* %11 to double*
- store double %10, double* %12, align 8
+ %9 = mul i64 %7, 1
+ %10 = add i64 %5, %9
+ %11 = inttoptr i64 %10 to i8*
+ %12 = load i8, i8* %11, align 1
+ %13 = trunc i8 %12 to i2
+ %14 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %4, i64 %7)
+ %15 = bitcast i8* %14 to i2*
+ store i2 %13, i2* %15, align 1
br label %exiting__1
exiting__1: ; preds = %body__1
- %13 = add i64 %5, 1
+ %16 = add i64 %7, 1
br label %header__1
exit__1: ; preds = %header__1
- br label %next
+ %17 = call %String* @__quantum__rt__string_create(i32 0, i8* %str)
+ %18 = load %Result*, %Result** @ResultZero, align 8
+ %19 = load %Result*, %Result** @ResultOne, align 8
+ %20 = icmp eq i8 %res, 0
+ %21 = select i1 %20, %Result* %18, %Result* %19
+ %22 = getelementptr { i64, i64, i64 }, { i64, i64, i64 }* %range, i64 0, i32 0
+ %23 = load i64, i64* %22, align 4
+ %24 = getelementptr { i64, i64, i64 }, { i64, i64, i64 }* %range, i64 0, i32 1
+ %25 = load i64, i64* %24, align 4
+ %26 = getelementptr { i64, i64, i64 }, { i64, i64, i64 }* %range, i64 0, i32 2
+ %27 = load i64, i64* %26, align 4
+ %28 = load %Range, %Range* @EmptyRange, align 4
+ %29 = insertvalue %Range %28, i64 %23, 0
+ %30 = insertvalue %Range %29, i64 %25, 1
+ %31 = insertvalue %Range %30, i64 %27, 2
+ %32 = trunc i8 %b to i1
+ %33 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ i64, i1 }* getelementptr ({ i64, i1 }, { i64, i1 }* null, i32 1) to i64))
+ %34 = bitcast %Tuple* %33 to { i64, i1 }*
+ %35 = getelementptr inbounds { i64, i1 }, { i64, i1 }* %34, i32 0, i32 0
+ %36 = getelementptr inbounds { i64, i1 }, { i64, i1 }* %34, i32 0, i32 1
+ store i64 %cnt, i64* %35, align 4
+ store i1 %32, i1* %36, align 1
+ %37 = call { %Array*, %String*, %Result*, %Range, { i64, i1 }* }* @Microsoft__Quantum__Testing__QIR__TestEntryPoint__body(%Array* %4, %String* %17, %Result* %21, %Range %31, { i64, i1 }* %34)
+ %38 = getelementptr inbounds { %Array*, %String*, %Result*, %Range, { i64, i1 }* }, { %Array*, %String*, %Result*, %Range, { i64, i1 }* }* %37, i32 0, i32 0
+ %39 = getelementptr inbounds { %Array*, %String*, %Result*, %Range, { i64, i1 }* }, { %Array*, %String*, %Result*, %Range, { i64, i1 }* }* %37, i32 0, i32 1
+ %40 = getelementptr inbounds { %Array*, %String*, %Result*, %Range, { i64, i1 }* }, { %Array*, %String*, %Result*, %Range, { i64, i1 }* }* %37, i32 0, i32 2
+ %41 = getelementptr inbounds { %Array*, %String*, %Result*, %Range, { i64, i1 }* }, { %Array*, %String*, %Result*, %Range, { i64, i1 }* }* %37, i32 0, i32 3
+ %42 = getelementptr inbounds { %Array*, %String*, %Result*, %Range, { i64, i1 }* }, { %Array*, %String*, %Result*, %Range, { i64, i1 }* }* %37, i32 0, i32 4
+ %43 = load %Array*, %Array** %38, align 8
+ %44 = load %String*, %String** %39, align 8
+ %45 = load %Result*, %Result** %40, align 8
+ %46 = load %Range, %Range* %41, align 4
+ %47 = load { i64, i1 }*, { i64, i1 }** %42, align 8
+ %48 = call i64 @__quantum__rt__array_get_size_1d(%Array* %43)
+ %49 = mul i64 %48, 1
+ %50 = call i8* @__quantum__rt__heap_alloc(i64 %49)
+ %51 = ptrtoint i8* %50 to i64
+ %52 = sub i64 %48, 1
+ br label %header__2
+
+header__2: ; preds = %exiting__2, %exit__1
+ %53 = phi i64 [ 0, %exit__1 ], [ %62, %exiting__2 ]
+ %54 = icmp sle i64 %53, %52
+ br i1 %54, label %body__2, label %exit__2
+
+body__2: ; preds = %header__2
+ %55 = mul i64 %53, 1
+ %56 = add i64 %51, %55
+ %57 = inttoptr i64 %56 to i8*
+ %58 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %43, i64 %53)
+ %59 = bitcast i8* %58 to i2*
+ %60 = load i2, i2* %59, align 1
+ %61 = sext i2 %60 to i8
+ store i8 %61, i8* %57, align 1
+ br label %exiting__2
+
+exiting__2: ; preds = %body__2
+ %62 = add i64 %53, 1
+ br label %header__2
+
+exit__2: ; preds = %header__2
+ %63 = call i8* @__quantum__rt__heap_alloc(i64 ptrtoint ({ i64, i8* }* getelementptr ({ i64, i8* }, { i64, i8* }* null, i32 1) to i64))
+ %64 = bitcast i8* %63 to { i64, i8* }*
+ %65 = getelementptr { i64, i8* }, { i64, i8* }* %64, i64 0, i32 0
+ store i64 %48, i64* %65, align 4
+ %66 = getelementptr { i64, i8* }, { i64, i8* }* %64, i64 0, i32 1
+ store i8* %50, i8** %66, align 8
+ %67 = call i32 @__quantum__rt__string_get_length(%String* %44)
+ %68 = sext i32 %67 to i64
+ %69 = call i8* @__quantum__rt__string_get_data(%String* %44)
+ %70 = call i8* @__quantum__rt__heap_alloc(i64 %68)
+ call void @llvm.memcpy.p0i8.p0i8.i64(i8* %70, i8* %69, i64 %68, i1 false)
+ %71 = load %Result*, %Result** @ResultZero, align 8
+ %72 = call i1 @__quantum__rt__result_equal(%Result* %45, %Result* %71)
+ %73 = select i1 %72, i8 0, i8 -1
+ %74 = extractvalue %Range %46, 0
+ %75 = extractvalue %Range %46, 1
+ %76 = extractvalue %Range %46, 2
+ %77 = call i8* @__quantum__rt__heap_alloc(i64 mul nuw (i64 ptrtoint (i64* getelementptr (i64, i64* null, i32 1) to i64), i64 3))
+ %78 = bitcast i8* %77 to { i64, i64, i64 }*
+ %79 = getelementptr { i64, i64, i64 }, { i64, i64, i64 }* %78, i64 0, i32 0
+ store i64 %74, i64* %79, align 4
+ %80 = getelementptr { i64, i64, i64 }, { i64, i64, i64 }* %78, i64 0, i32 1
+ store i64 %75, i64* %80, align 4
+ %81 = getelementptr { i64, i64, i64 }, { i64, i64, i64 }* %78, i64 0, i32 2
+ store i64 %76, i64* %81, align 4
+ %82 = getelementptr inbounds { i64, i1 }, { i64, i1 }* %47, i32 0, i32 0
+ %83 = getelementptr inbounds { i64, i1 }, { i64, i1 }* %47, i32 0, i32 1
+ %84 = load i64, i64* %82, align 4
+ %85 = load i1, i1* %83, align 1
+ %86 = sext i1 %85 to i8
+ %87 = call i8* @__quantum__rt__heap_alloc(i64 ptrtoint ({ i64, i8 }* getelementptr ({ i64, i8 }, { i64, i8 }* null, i32 1) to i64))
+ %88 = bitcast i8* %87 to { i64, i8 }*
+ %89 = getelementptr { i64, i8 }, { i64, i8 }* %88, i64 0, i32 0
+ store i64 %84, i64* %89, align 4
+ %90 = getelementptr { i64, i8 }, { i64, i8 }* %88, i64 0, i32 1
+ store i8 %86, i8* %90, align 1
+ %91 = call i8* @__quantum__rt__heap_alloc(i64 ptrtoint ({ { i64, i8* }*, i8*, i8, { i64, i64, i64 }*, { i64, i8 }* }* getelementptr ({ { i64, i8* }*, i8*, i8, { i64, i64, i64 }*, { i64, i8 }* }, { { i64, i8* }*, i8*, i8, { i64, i64, i64 }*, { i64, i8 }* }* null, i32 1) to i64))
+ %92 = bitcast i8* %91 to { { i64, i8* }*, i8*, i8, { i64, i64, i64 }*, { i64, i8 }* }*
+ %93 = getelementptr { { i64, i8* }*, i8*, i8, { i64, i64, i64 }*, { i64, i8 }* }, { { i64, i8* }*, i8*, i8, { i64, i64, i64 }*, { i64, i8 }* }* %92, i64 0, i32 0
+ store { i64, i8* }* %64, { i64, i8* }** %93, align 8
+ %94 = getelementptr { { i64, i8* }*, i8*, i8, { i64, i64, i64 }*, { i64, i8 }* }, { { i64, i8* }*, i8*, i8, { i64, i64, i64 }*, { i64, i8 }* }* %92, i64 0, i32 1
+ store i8* %70, i8** %94, align 8
+ %95 = getelementptr { { i64, i8* }*, i8*, i8, { i64, i64, i64 }*, { i64, i8 }* }, { { i64, i8* }*, i8*, i8, { i64, i64, i64 }*, { i64, i8 }* }* %92, i64 0, i32 2
+ store i8 %73, i8* %95, align 1
+ %96 = getelementptr { { i64, i8* }*, i8*, i8, { i64, i64, i64 }*, { i64, i8 }* }, { { i64, i8* }*, i8*, i8, { i64, i64, i64 }*, { i64, i8 }* }* %92, i64 0, i32 3
+ store { i64, i64, i64 }* %78, { i64, i64, i64 }** %96, align 8
+ %97 = getelementptr { { i64, i8* }*, i8*, i8, { i64, i64, i64 }*, { i64, i8 }* }, { { i64, i8* }*, i8*, i8, { i64, i64, i64 }*, { i64, i8 }* }* %92, i64 0, i32 4
+ store { i64, i8 }* %88, { i64, i8 }** %97, align 8
+ call void @__quantum__rt__array_update_reference_count(%Array* %4, i64 -1)
+ call void @__quantum__rt__string_update_reference_count(%String* %17, i64 -1)
+ call void @__quantum__rt__tuple_update_reference_count(%Tuple* %33, i64 -1)
+ call void @__quantum__rt__array_update_reference_count(%Array* %43, i64 -1)
+ call void @__quantum__rt__string_update_reference_count(%String* %44, i64 -1)
+ call void @__quantum__rt__result_update_reference_count(%Result* %45, i64 -1)
+ %98 = bitcast { i64, i1 }* %47 to %Tuple*
+ call void @__quantum__rt__tuple_update_reference_count(%Tuple* %98, i64 -1)
+ %99 = bitcast { %Array*, %String*, %Result*, %Range, { i64, i1 }* }* %37 to %Tuple*
+ call void @__quantum__rt__tuple_update_reference_count(%Tuple* %99, i64 -1)
+ ret { { i64, i8* }*, i8*, i8, { i64, i64, i64 }*, { i64, i8 }* }* %92
}
diff --git a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestEntryPoint.qs b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestEntryPoint.qs
index 37947d5eac..15f78d61c2 100644
--- a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestEntryPoint.qs
+++ b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestEntryPoint.qs
@@ -1,20 +1,22 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
-namespace Microsoft.Quantum.Testing.QIR
-{
- //open Microsoft.Quantum.Intrinsic;
+namespace Microsoft.Quantum.Testing.QIR {
@EntryPoint()
- operation TestEntryPoint(a : Double[], b : Bool) : Double
- {
+ operation TestEntryPoint(
+ arr : Pauli[], str : String, res : Result, range : Range, (cnt : Int, b : Bool))
+ : (Pauli[], String, Result, Range, (Int, Bool)) {
+
mutable sum = 0.0;
mutable flag = b;
- for (i in a)
+ for pauli in arr
{
- set sum = sum + (flag ? i | -i);
+ let value = pauli == PauliI ? 0. | 1.;
+ set sum = sum + (flag ? value | -value);
set flag = not flag;
}
- return sum;
+
+ return (arr, str, res, range, (cnt, b));
}
}
diff --git a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestForLoop.ll b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestForLoop.ll
index e00d808705..f53eb66522 100644
--- a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestForLoop.ll
+++ b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestForLoop.ll
@@ -1,6 +1,6 @@
define { double, %String* }* @Microsoft__Quantum__Testing__QIR__TestNestedLoops__body() {
entry:
- %name = call %String* @__quantum__rt__string_create(i32 6, i8* getelementptr inbounds ([7 x i8], [7 x i8]* @0, i32 0, i32 0))
+ %name = call %String* @__quantum__rt__string_create(i32 0, i8* getelementptr inbounds ([7 x i8], [7 x i8]* @0, i32 0, i32 0))
%0 = call %String* @__quantum__rt__string_create(i32 0, i8* null)
%1 = call { double, %String* }* @Microsoft__Quantum__Testing__QIR__Energy__body(double 0.000000e+00, %String* %0)
%res = alloca { double, %String* }*, align 8
diff --git a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestOpArgument.ll b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestOpArgument.ll
index 04becbf097..c67ef8d759 100644
--- a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestOpArgument.ll
+++ b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestOpArgument.ll
@@ -1,4 +1,4 @@
-define %String* @Microsoft__Quantum__Testing__QIR__TestOpArgument__body() #0 {
+define %String* @Microsoft__Quantum__Testing__QIR__TestOpArgument__body() {
entry:
%q1 = call %Qubit* @__quantum__rt__qubit_allocate()
%q2 = call %Qubit* @__quantum__rt__qubit_allocate()
diff --git a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestPartials1.ll b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestPartials1.ll
index afa12b5f5a..6f64b6c225 100644
--- a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestPartials1.ll
+++ b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestPartials1.ll
@@ -1,4 +1,4 @@
-define i1 @Microsoft__Quantum__Testing__QIR__TestPartials__body(i64 %a, double %b) #0 {
+define i1 @Microsoft__Quantum__Testing__QIR__TestPartials__body(i64 %a, double %b) {
entry:
%0 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ %Callable*, double }* getelementptr ({ %Callable*, double }, { %Callable*, double }* null, i32 1) to i64))
%1 = bitcast %Tuple* %0 to { %Callable*, double }*
diff --git a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestRepeat.ll b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestRepeat.ll
index a51c37012c..102dcfecc1 100644
--- a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestRepeat.ll
+++ b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestRepeat.ll
@@ -9,7 +9,7 @@ repeat__1: ; preds = %condContinue__2, %e
call void @__quantum__qis__x__body(%Qubit* %q)
call void @__quantum__qis__t__adj(%Qubit* %q)
call void @__quantum__qis__h__body(%Qubit* %q)
- %name = call %String* @__quantum__rt__string_create(i32 6, i8* getelementptr inbounds ([7 x i8], [7 x i8]* @0, i32 0, i32 0))
+ %name = call %String* @__quantum__rt__string_create(i32 0, i8* getelementptr inbounds ([7 x i8], [7 x i8]* @0, i32 0, i32 0))
%0 = call %String* @__quantum__rt__string_create(i32 0, i8* null)
%1 = call { double, %String* }* @Microsoft__Quantum__Testing__QIR__Energy__body(double 0.000000e+00, %String* %0)
%res = alloca { double, %String* }*, align 8
@@ -57,7 +57,7 @@ fixup__1: ; preds = %until__1
br i1 %15, label %then0__1, label %continue__1
then0__1: ; preds = %fixup__1
- %16 = call %String* @__quantum__rt__string_create(i32 19, i8* getelementptr inbounds ([20 x i8], [20 x i8]* @1, i32 0, i32 0))
+ %16 = call %String* @__quantum__rt__string_create(i32 0, i8* getelementptr inbounds ([20 x i8], [20 x i8]* @1, i32 0, i32 0))
%17 = load %String*, %String** %3, align 8
%18 = load %String*, %String** %8, align 8
%19 = load { double, %String* }*, { double, %String* }** %res, align 8
diff --git a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestStrings.ll b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestStrings.ll
index dcb3bf3816..9b253102fa 100644
--- a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestStrings.ll
+++ b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestStrings.ll
@@ -1,27 +1,27 @@
define %String* @Microsoft__Quantum__Testing__QIR__TestStrings__body(i64 %a, i64 %b) {
entry:
- %0 = call %String* @__quantum__rt__string_create(i32 5, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @0, i32 0, i32 0))
+ %0 = call %String* @__quantum__rt__string_create(i32 0, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @0, i32 0, i32 0))
%1 = call %String* @__quantum__rt__int_to_string(i64 %a)
%2 = call %String* @__quantum__rt__string_concatenate(%String* %0, %String* %1)
call void @__quantum__rt__string_update_reference_count(%String* %0, i64 -1)
call void @__quantum__rt__string_update_reference_count(%String* %1, i64 -1)
- %3 = call %String* @__quantum__rt__string_create(i32 5, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @1, i32 0, i32 0))
+ %3 = call %String* @__quantum__rt__string_create(i32 0, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @1, i32 0, i32 0))
%x = call %String* @__quantum__rt__string_concatenate(%String* %2, %String* %3)
call void @__quantum__rt__string_update_reference_count(%String* %2, i64 -1)
call void @__quantum__rt__string_update_reference_count(%String* %3, i64 -1)
- %4 = call %String* @__quantum__rt__string_create(i32 7, i8* getelementptr inbounds ([8 x i8], [8 x i8]* @2, i32 0, i32 0))
+ %4 = call %String* @__quantum__rt__string_create(i32 0, i8* getelementptr inbounds ([8 x i8], [8 x i8]* @2, i32 0, i32 0))
%5 = add i64 %a, %b
%6 = call %String* @__quantum__rt__int_to_string(i64 %5)
%y = call %String* @__quantum__rt__string_concatenate(%String* %4, %String* %6)
call void @__quantum__rt__string_update_reference_count(%String* %4, i64 -1)
call void @__quantum__rt__string_update_reference_count(%String* %6, i64 -1)
call void @__quantum__rt__string_update_reference_count(%String* %y, i64 1)
- %7 = call %String* @__quantum__rt__string_create(i32 16, i8* getelementptr inbounds ([17 x i8], [17 x i8]* @3, i32 0, i32 0))
+ %7 = call %String* @__quantum__rt__string_create(i32 0, i8* getelementptr inbounds ([17 x i8], [17 x i8]* @3, i32 0, i32 0))
%8 = call %String* @__quantum__rt__double_to_string(double 1.200000e+00)
%9 = call %String* @__quantum__rt__string_concatenate(%String* %7, %String* %8)
call void @__quantum__rt__string_update_reference_count(%String* %7, i64 -1)
call void @__quantum__rt__string_update_reference_count(%String* %8, i64 -1)
- %10 = call %String* @__quantum__rt__string_create(i32 6, i8* getelementptr inbounds ([7 x i8], [7 x i8]* @4, i32 0, i32 0))
+ %10 = call %String* @__quantum__rt__string_create(i32 0, i8* getelementptr inbounds ([7 x i8], [7 x i8]* @4, i32 0, i32 0))
%11 = call %String* @__quantum__rt__string_concatenate(%String* %9, %String* %10)
call void @__quantum__rt__string_update_reference_count(%String* %9, i64 -1)
call void @__quantum__rt__string_update_reference_count(%String* %10, i64 -1)
@@ -29,7 +29,7 @@ entry:
%13 = call %String* @__quantum__rt__string_concatenate(%String* %11, %String* %12)
call void @__quantum__rt__string_update_reference_count(%String* %11, i64 -1)
call void @__quantum__rt__string_update_reference_count(%String* %12, i64 -1)
- %14 = call %String* @__quantum__rt__string_create(i32 7, i8* getelementptr inbounds ([8 x i8], [8 x i8]* @5, i32 0, i32 0))
+ %14 = call %String* @__quantum__rt__string_create(i32 0, i8* getelementptr inbounds ([8 x i8], [8 x i8]* @5, i32 0, i32 0))
%15 = call %String* @__quantum__rt__string_concatenate(%String* %13, %String* %14)
call void @__quantum__rt__string_update_reference_count(%String* %13, i64 -1)
call void @__quantum__rt__string_update_reference_count(%String* %14, i64 -1)
@@ -38,7 +38,7 @@ entry:
%18 = call %String* @__quantum__rt__string_concatenate(%String* %15, %String* %17)
call void @__quantum__rt__string_update_reference_count(%String* %15, i64 -1)
call void @__quantum__rt__string_update_reference_count(%String* %17, i64 -1)
- %19 = call %String* @__quantum__rt__string_create(i32 8, i8* getelementptr inbounds ([9 x i8], [9 x i8]* @6, i32 0, i32 0))
+ %19 = call %String* @__quantum__rt__string_create(i32 0, i8* getelementptr inbounds ([9 x i8], [9 x i8]* @6, i32 0, i32 0))
%20 = call %String* @__quantum__rt__string_concatenate(%String* %18, %String* %19)
call void @__quantum__rt__string_update_reference_count(%String* %18, i64 -1)
call void @__quantum__rt__string_update_reference_count(%String* %19, i64 -1)
@@ -47,7 +47,7 @@ entry:
%23 = call %String* @__quantum__rt__string_concatenate(%String* %20, %String* %22)
call void @__quantum__rt__string_update_reference_count(%String* %20, i64 -1)
call void @__quantum__rt__string_update_reference_count(%String* %22, i64 -1)
- %24 = call %String* @__quantum__rt__string_create(i32 8, i8* getelementptr inbounds ([9 x i8], [9 x i8]* @7, i32 0, i32 0))
+ %24 = call %String* @__quantum__rt__string_create(i32 0, i8* getelementptr inbounds ([9 x i8], [9 x i8]* @7, i32 0, i32 0))
%25 = call %String* @__quantum__rt__string_concatenate(%String* %23, %String* %24)
call void @__quantum__rt__string_update_reference_count(%String* %23, i64 -1)
call void @__quantum__rt__string_update_reference_count(%String* %24, i64 -1)
@@ -56,7 +56,7 @@ entry:
%28 = call %String* @__quantum__rt__string_concatenate(%String* %25, %String* %27)
call void @__quantum__rt__string_update_reference_count(%String* %25, i64 -1)
call void @__quantum__rt__string_update_reference_count(%String* %27, i64 -1)
- %29 = call %String* @__quantum__rt__string_create(i32 7, i8* getelementptr inbounds ([8 x i8], [8 x i8]* @8, i32 0, i32 0))
+ %29 = call %String* @__quantum__rt__string_create(i32 0, i8* getelementptr inbounds ([8 x i8], [8 x i8]* @8, i32 0, i32 0))
%30 = call %String* @__quantum__rt__string_concatenate(%String* %28, %String* %29)
call void @__quantum__rt__string_update_reference_count(%String* %28, i64 -1)
call void @__quantum__rt__string_update_reference_count(%String* %29, i64 -1)
@@ -68,7 +68,7 @@ entry:
%i = call %String* @__quantum__rt__string_concatenate(%String* %30, %String* %35)
call void @__quantum__rt__string_update_reference_count(%String* %30, i64 -1)
call void @__quantum__rt__string_update_reference_count(%String* %35, i64 -1)
- %36 = call %String* @__quantum__rt__string_create(i32 7, i8* getelementptr inbounds ([8 x i8], [8 x i8]* @9, i32 0, i32 0))
+ %36 = call %String* @__quantum__rt__string_create(i32 0, i8* getelementptr inbounds ([8 x i8], [8 x i8]* @9, i32 0, i32 0))
call void @__quantum__rt__string_update_reference_count(%String* %x, i64 1)
%37 = call %String* @__quantum__rt__string_concatenate(%String* %36, %String* %x)
call void @__quantum__rt__string_update_reference_count(%String* %36, i64 -1)
diff --git a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestUdtArgument.ll b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestUdtArgument.ll
index 7f67653db0..ec4ca41e52 100644
--- a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestUdtArgument.ll
+++ b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestUdtArgument.ll
@@ -1,4 +1,4 @@
-define { i64, { i2, i64 }* }* @Microsoft__Quantum__Testing__QIR__TestUdtArgument__body() #0 {
+define { i64, { i2, i64 }* }* @Microsoft__Quantum__Testing__QIR__TestUdtArgument__body() {
entry:
%0 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Testing__QIR__TestType1, [2 x void (%Tuple*, i64)*]* null, %Tuple* null)
%udt1 = call { i64 }* @Microsoft__Quantum__Testing__QIR_____GUID___Build__body(%Callable* %0)
diff --git a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestUdtUpdate1.ll b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestUdtUpdate1.ll
index 596a2ef762..f2600307aa 100644
--- a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestUdtUpdate1.ll
+++ b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestUdtUpdate1.ll
@@ -43,7 +43,7 @@ condFalse__1: ; preds = %entry
condContinue__1: ; preds = %condFalse__1, %entry
store { double, %String* }* %19, { double, %String* }** %14, align 8
%20 = getelementptr inbounds { double, %String* }, { double, %String* }* %19, i32 0, i32 1
- %21 = call %String* @__quantum__rt__string_create(i32 5, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @0, i32 0, i32 0))
+ %21 = call %String* @__quantum__rt__string_create(i32 0, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @0, i32 0, i32 0))
call void @__quantum__rt__string_update_reference_count(%String* %21, i64 1)
%22 = load %String*, %String** %20, align 8
br i1 %12, label %condContinue__2, label %condFalse__2
diff --git a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestUdtUpdate2.ll b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestUdtUpdate2.ll
index fd92802fa4..831081ddc0 100644
--- a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestUdtUpdate2.ll
+++ b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestUdtUpdate2.ll
@@ -21,7 +21,7 @@ entry:
call void @__quantum__rt__tuple_update_reference_count(%Tuple* %2, i64 1)
call void @__quantum__rt__tuple_update_reference_count(%Tuple* %5, i64 1)
call void @__quantum__rt__tuple_update_reference_count(%Tuple* %6, i64 1)
- %9 = call %String* @__quantum__rt__string_create(i32 4, i8* getelementptr inbounds ([5 x i8], [5 x i8]* @1, i32 0, i32 0))
+ %9 = call %String* @__quantum__rt__string_create(i32 0, i8* getelementptr inbounds ([5 x i8], [5 x i8]* @1, i32 0, i32 0))
%10 = call i1 @__quantum__rt__string_equal(%String* %8, %String* %9)
br i1 %10, label %then0__1, label %continue__1
diff --git a/src/QsCompiler/Tests.Compiler/Tests.Compiler.fsproj b/src/QsCompiler/Tests.Compiler/Tests.Compiler.fsproj
index 182557169e..9a5ddf6695 100644
--- a/src/QsCompiler/Tests.Compiler/Tests.Compiler.fsproj
+++ b/src/QsCompiler/Tests.Compiler/Tests.Compiler.fsproj
@@ -21,11 +21,11 @@
-
- Always
+
+ Always
-
- Always
+
+ Always
Always