diff --git a/examples/QIR/QirTarget.qs b/examples/QIR/QirTarget.qs index b259ec10b0..938b0c7a23 100644 --- a/examples/QIR/QirTarget.qs +++ b/examples/QIR/QirTarget.qs @@ -122,6 +122,24 @@ namespace Microsoft.Quantum.Intrinsic { return PhysMeasure(bases, qubits); } + operation MResetZ(qb : Qubit) : Result + { + let res = Mz(qb); + if (res == One) + { + X(qb); + } + return res; + } + + operation Reset(qb : Qubit) : Unit + { + if (Mz(qb) == One) + { + X(qb); + } + } + @Inline() operation Rx(theta : Double, qb : Qubit) : Unit is Adj { @@ -137,7 +155,7 @@ namespace Microsoft.Quantum.Intrinsic { @Inline() operation Rz(theta : Double, qb : Qubit) : Unit - is Adj { + is Adj + Ctl { body (...) { PhysRz(theta, qb); @@ -146,6 +164,20 @@ namespace Microsoft.Quantum.Intrinsic { { PhysRz(-theta, qb); } + controlled (ctls, ...) + { + PhysRz(theta / 2.0, qb); + CNOT(ctls[0], qb); + PhysRz(-theta / 2.0, qb); + CNOT(ctls[0], qb); + } + controlled adjoint (ctls, ...) + { + PhysRz(-theta / 2.0, qb); + CNOT(ctls[0], qb); + PhysRz(theta / 2.0, qb); + CNOT(ctls[0], qb); + } } @Inline() @@ -163,4 +195,10 @@ namespace Microsoft.Quantum.Intrinsic { { return IntAsDoubleImpl(i); } + + @Inline() + function PI() : Double + { + return 3.14159265357989; + } } diff --git a/src/QsCompiler/QirGenerator/GenerationContext.cs b/src/QsCompiler/QirGenerator/GenerationContext.cs index ec5be01f59..f8d63be954 100644 --- a/src/QsCompiler/QirGenerator/GenerationContext.cs +++ b/src/QsCompiler/QirGenerator/GenerationContext.cs @@ -12,6 +12,7 @@ using Llvm.NET.Interop; using Llvm.NET.Types; using Llvm.NET.Values; +using Microsoft.Quantum.QsCompiler.DataTypes; using Microsoft.Quantum.QsCompiler.SyntaxTokens; using Microsoft.Quantum.QsCompiler.SyntaxTree; @@ -515,7 +516,74 @@ IEnumerable ArgTupleToTypes(QsArgumentTuple arg) /// The specialization's argument tuple public void GenerateFunctionHeader(QsSpecialization spec, QsArgumentTuple argTuple) { - IEnumerable ArgTupleToNames(QsArgumentTuple arg) + // void ProcessSubArg(QsArgumentTuple arg, Value val) + // { + // switch (arg) + // { + // case QsArgumentTuple.QsTuple tuple: + // var items = tuple.Item; + // var n = items.Length; + // if (n > 0) + // { + // ITypeRef tupleTypeRef = this.BuildArgTupleType(arg); + // // Convert value from TuplePointer to the proper type + // Value asStructPointer = this.CurrentBuilder.BitCast(val, + // tupleTypeRef.CreatePointerType()); + // var indices = new Value[] { this.CurrentContext.CreateConstant(0L), + // this.CurrentContext.CreateConstant(1) }; + // for (var i = 0; i < n; i++) + // { + // indices[1] = this.CurrentContext.CreateConstant(i + 1); + // Value ptr = this.CurrentBuilder.GetElementPtr(tupleTypeRef, asStructPointer, indices); + //#pragma warning disable CS0618 // Type or member is obsolete -- computing the type that ptr points to is tricky, so we just rely on it's .NativeType + // var subVal = this.CurrentBuilder.Load(ptr); + //#pragma warning restore CS0618 // Type or member is obsolete + // ProcessSubArg(tuple.Item[i], subVal); + // } + // } + // break; + // case QsArgumentTuple.QsTupleItem item: + // var argName = (item.Item.VariableName as QsLocalSymbol.ValidName).Item.Value; + // namesInScope.Peek().Add(argName, (val, false)); + // break; + // } + // } + + // void ProcessTopLevelArg(QsArgumentTuple arg, int index) + // { + // // Register the parameter name + // var argName = arg switch + // { + // QsArgumentTuple.QsTupleItem item => (item.Item.VariableName as QsLocalSymbol.ValidName).Item.Value, + // _ => this.GenerateUniqueName("arg") + // }; + // this.CurrentFunction.Parameters[index].Name = argName; + // namesInScope.Peek().Add(argName, (this.CurrentFunction.Parameters[index], false)); + + // // If the arg is a sub-tuple, process it + // if (arg.IsQsTuple) + // { + // ProcessSubArg(arg, this.CurrentFunction.Parameters[index]); + // } + // } + + // this.CurrentFunction = this.RegisterFunction(spec, argTuple); + // this.CurrentBlock = this.CurrentFunction.AppendBasicBlock("entry"); + // this.CurrentBuilder = new InstructionBuilder(this.CurrentBlock); + + // this.namesInScope.Push(new Dictionary()); + // var topLevelArgs = argTuple switch + // { + // QsArgumentTuple.QsTuple tuple => tuple.Item, + // _ => new QsArgumentTuple[] { argTuple }.ToImmutableArray() + // }; + // var i = 0; + // foreach (var arg in topLevelArgs) + // { + // ProcessTopLevelArg(arg, i); + // i++; + // } + IEnumerable ArgTupleToNames(QsArgumentTuple arg, Queue<(string, QsArgumentTuple)> tupleQueue) { string LocalVarName(QsArgumentTuple v) { @@ -525,7 +593,9 @@ string LocalVarName(QsArgumentTuple v) } else { - return this.GenerateUniqueName("arg"); + var name = this.GenerateUniqueName("arg"); + tupleQueue.Enqueue((name, v)); + return name; } } @@ -544,13 +614,30 @@ string LocalVarName(QsArgumentTuple v) this.CurrentBuilder = new InstructionBuilder(this.CurrentBlock); namesInScope.Push(new Dictionary()); + var pendingTuples = new Queue<(string, QsArgumentTuple)>(); var i = 0; - foreach (var argName in ArgTupleToNames(argTuple)) + foreach (var argName in ArgTupleToNames(argTuple, pendingTuples)) { this.CurrentFunction.Parameters[i].Name = argName; namesInScope.Peek().Add(argName, (this.CurrentFunction.Parameters[i], false)); i++; } + + // Now break up input tuples + while (pendingTuples.TryDequeue(out (string, QsArgumentTuple) tuple)) + { + var (tupleArgName, tupleArg) = tuple; + this.PushNamedValue(tupleArgName); + var tupleValue = this.ValueStack.Pop(); + int idx = 1; + foreach (var argName in ArgTupleToNames(tupleArg, pendingTuples)) + { + var elementPointer = this.GetTupleElementPointer((tupleValue.NativeType as IPointerType).ElementType, tupleValue, idx); + var element = this.CurrentBuilder.Load((elementPointer.NativeType as IPointerType).ElementType, elementPointer); + namesInScope.Peek().Add(argName, (element, false)); + idx++; + } + } } /// @@ -590,8 +677,7 @@ public void GenerateConstructor(QsCustomType udt) for (int i = 0; i < args.Length; i++) { this.CurrentFunction.Parameters[i].Name = $"arg{i}"; - var itemPtr = this.CurrentBuilder.GetStructElementPointer(udtTupleType, - udtTuple, (uint)i + 1); + var itemPtr = this.GetTupleElementPointer(udtTupleType, udtTuple, i + 1); this.CurrentBuilder.Store(this.CurrentFunction.Parameters[i], itemPtr); // Add a reference to the value, if necessary this.AddRef(this.CurrentFunction.Parameters[i]); @@ -1074,6 +1160,29 @@ internal Value CreateTupleForType(ITypeRef t) return tuple; } + /// + /// Returns a pointer to a tuple element. + /// This is a thin wrapper around the LLVM GEP instruction. + /// + /// The type of the tuple structure (not the type of the pointer!). + /// The pointer to the tuple. This will be cast to the proper type if necessary. + /// The element's index into the tuple. The tuple header is index 0, the first data item is index 1. + /// An optional InstructionBuilder to create these instructions on. The current builder is used as the default. + /// + internal Value GetTupleElementPointer(ITypeRef t, Value tuple, int index, InstructionBuilder b = null) + { + Value[] indices = new Value[] { + this.CurrentContext.CreateConstant(0L), + this.CurrentContext.CreateConstant(index) + }; + var builder = b ?? this.CurrentBuilder; + var typedTuple = tuple.NativeType == t.CreatePointerType() + ? tuple + : builder.BitCast(tuple, t.CreatePointerType()); + var elementPointer = builder.GetElementPtr(t, typedTuple, indices); + return elementPointer; + } + /// /// Creates and returns a deep copy of a tuple. /// By default this uses the current builder, but an alternate builder may be provided. @@ -1098,8 +1207,7 @@ internal Value DeepCopyTuple(Value original, ResolvedType t, InstructionBuilder for (int i = 0; i < elementTypes.Length; i++) { var elementType = elementTypes[i]; - var originalElementPointer = builder.GetStructElementPointer(originalTypeRef, - typedOriginal, (uint)i + 1); + var originalElementPointer = this.GetTupleElementPointer(originalTypeRef, typedOriginal, i + 1, builder); var originalElement = builder.Load(this.LlvmTypeFromQsharpType(elementType), originalElementPointer); Value elementValue = elementType.Resolution switch @@ -1110,8 +1218,7 @@ internal Value DeepCopyTuple(Value original, ResolvedType t, InstructionBuilder builder.Call(this.GetRuntimeFunction("array_copy"), originalElement), _ => originalElement, }; - var copyElementPointer = builder.GetStructElementPointer(originalTypeRef, - typedCopy, (uint)i + 1); + var copyElementPointer = this.GetTupleElementPointer(originalTypeRef, typedCopy, i + 1, builder); builder.Store(elementValue, copyElementPointer); } @@ -1229,12 +1336,14 @@ void FillStructSlot(ITypeRef structType, Value pointerToStruct, Value fillValue, this.CurrentContext.CreateConstant(position) }; var elementPointer = this.CurrentBuilder.GetElementPtr(structType, pointerToStruct, indices); - this.CurrentBuilder.Store(fillValue, elementPointer); + var castValue = fillValue.NativeType == this.QirTuplePointer + ? this.CurrentBuilder.BitCast(fillValue, (structType as IStructType).Members[position]) + : fillValue; + this.CurrentBuilder.Store(castValue, elementPointer); } void FillItem(ITypeRef structType, Value pointerToStruct, TypedExpression fillExpr, int position) { - Contract.Assert(!fillExpr.ResolvedType.Resolution.IsTupleType, "FillItem is for non-tuple items only"); this.Transformation.Expressions.OnTypedExpression(fillExpr); var fillValue = this.ValueStack.Pop(); FillStructSlot(structType, pointerToStruct, fillValue, position); @@ -1251,10 +1360,11 @@ void FillItem(ITypeRef structType, Value pointerToStruct, TypedExpression fillEx { case ResolvedExpression.ValueTuple _: // Handle inner tuples: allocate space. initialize, and then recurse - var subTupleTypeRef = this.LlvmTypeFromQsharpType(items[i].ResolvedType); + var subTupleTypeRef = (this.LlvmTypeFromQsharpType(items[i].ResolvedType) as IPointerType).ElementType; var subTupleAsTuplePointer = this.CreateTupleForType(subTupleTypeRef); - FillStructSlot(tupleTypeRef, tupleToFillPointer, subTupleAsTuplePointer, i + 1); - this.FillTuple(subTupleAsTuplePointer, items[i]); + var subTupleAsTypedPointer = this.CurrentBuilder.BitCast(subTupleAsTuplePointer, subTupleTypeRef.CreatePointerType()); + FillStructSlot(tupleTypeRef, tupleToFillPointer, subTupleAsTypedPointer, i + 1); + this.FillTuple(subTupleAsTypedPointer, items[i]); break; default: FillItem(tupleTypeRef, tupleToFillPointer, items[i], i + 1); @@ -1284,6 +1394,11 @@ internal void MapTuple(TypedExpression s, QsArgumentTuple d) void MapTupleInner(TypedExpression source, QsArgumentTuple destination, List<(string, Value)> assignmentQueue) { + if (source.Expression.IsUnitValue) + { + // Nothing to do, so bail + return; + } if (destination is QsArgumentTuple.QsTuple tuple) { var items = tuple.Item; @@ -1292,7 +1407,6 @@ void MapTupleInner(TypedExpression source, QsArgumentTuple destination, MapTupleInner(source, items[0], assignmentQueue); return; } - Contract.Assert(source.Expression.IsValueTuple, "Argument values are inconsistent with actual arguments while inlining"); var srcItems = (source.Expression as ResolvedExpression.ValueTuple).Item; foreach (var (ex, ti) in srcItems.Zip(items, (ex, ti) => (ex, ti))) { @@ -1333,7 +1447,7 @@ public GlobalVariable EnsureWrapperFor(QsCallable callable) for (var index = 0; index < 4; index++) { QsSpecializationKind kind = FunctionArray[index]; - if (callable.Specializations.Any(spec => spec.Kind == kind)) + if (callable.Specializations.Any(spec => spec.Kind == kind && spec.Implementation.IsProvided)) { var f = this.CurrentModule.AddFunction(CallableWrapperName(callable, kind), this.StandardWrapperSignature); @@ -1376,18 +1490,31 @@ bool GenerateWrapperHeader(QsCallable callable, QsSpecialization spec) // Generate the code that decomposes the tuple back into the named arguments // Note that we don't want to recurse here!!. - List GenerateArgTupleDecomposition(QsArgumentTuple arg, Value value) + List GenerateArgTupleDecomposition(QsArgumentTuple arg, Value value, QsSpecializationKind kind) { Value BuildLoadForArg(QsArgumentTuple arg, Value value) { ITypeRef argTypeRef = arg is QsArgumentTuple.QsTupleItem item ? this.BuildArgItemTupleType(item) - : this.QirTuplePointer; + : this.BuildArgTupleType(arg).CreatePointerType(); // value is a pointer to the argument Value actualArg = this.CurrentBuilder.Load(argTypeRef, value); return actualArg; } + // Controlled specializations have different signatures, so adjust what we have + if (kind.IsQsControlled || kind.IsQsControlledAdjoint) + { + var ctlArg = new LocalVariableDeclaration( + QsLocalSymbol.NewValidName(NonNullable.New(this.GenerateUniqueName("ctls"))), + ResolvedType.New(QsResolvedTypeKind.NewArrayType(ResolvedType.New(QsResolvedTypeKind.Qubit))), + new InferredExpressionInformation(false, false), + QsNullable.Null, + DataTypes.Range.Zero); + var ctlArgs = new QsArgumentTuple[] { QsArgumentTuple.NewQsTupleItem(ctlArg), arg }; + arg = QsArgumentTuple.NewQsTuple(ctlArgs.ToImmutableArray()); + } + List args = new List(); if (arg is QsArgumentTuple.QsTuple tuple) { @@ -1458,10 +1585,11 @@ Value GenerateBaseMethodCall(QsCallable callable, QsSpecialization spec, List Items = new List(); @@ -610,6 +617,7 @@ RebuildItem BuildPartialArgList(ResolvedType argType, TypedExpression arg, List< { var rebuild = new InnerArg() { + SharedState = this.SharedState, ArgIndex = remainingArgs.Count + 1, ItemType = this.SharedState.LlvmTypeFromQsharpType(argType) }; @@ -639,6 +647,7 @@ RebuildItem BuildPartialArgList(ResolvedType argType, TypedExpression arg, List< // callable var rebuild = new InnerCapture() { + SharedState = this.SharedState, CaptureIndex = capturedValues.Count + 2, ItemType = this.SharedState.LlvmTypeFromQsharpType(arg.ResolvedType) }; @@ -697,39 +706,74 @@ IrFunction BuildLiftedSpecialization(string name, QsSpecializationKind kind, ITy this.SharedState.ScopeMgr.OpenScope(); var capturePointer = builder.BitCast(func.Parameters[0], captureType.CreatePointerType()); - var parArgsPointer = builder.BitCast(func.Parameters[1], parArgsType.CreatePointerType()); Value innerArgTuple; if ((kind == QsSpecializationKind.QsControlled) || (kind == QsSpecializationKind.QsControlledAdjoint)) { // Deal with the extra control qubit arg for controlled and controlled-adjoint - var ctlArgsType = this.SharedState.CurrentContext.CreateStructType(false, - this.SharedState.QirTupleHeader, this.SharedState.QirArray, this.SharedState.QirTuplePointer); - var ctlArgsPointer = builder.BitCast(func.Parameters[1], ctlArgsType.CreatePointerType()); - var controlsPointer = builder.GetStructElementPointer(ctlArgsType.CreatePointerType(), - ctlArgsPointer, 1u); - var restPointer = builder.GetStructElementPointer(ctlArgsType.CreatePointerType(), ctlArgsPointer, 2u); - var typedRestPointer = builder.BitCast(restPointer, parArgsType.CreatePointerType()); - var restTuple = rebuild.BuildItem(builder, captureType, capturePointer, parArgsType, typedRestPointer); - var size = this.SharedState.ComputeSizeForType(ctlArgsType, builder); - innerArgTuple = builder.Call(this.SharedState.GetRuntimeFunction("tuple_create"), size); - var dummyTupleType = ResolvedType.New(QsResolvedTypeKind.NewTupleType( - (new ResolvedType[] { ResolvedType.New(QsResolvedTypeKind.MissingType) }).ToImmutableArray())); - this.SharedState.ScopeMgr.AddValue(innerArgTuple, dummyTupleType); - var typedNewTuple = builder.BitCast(innerArgTuple, ctlArgsType.CreatePointerType()); - var destControlsPointer = builder.GetStructElementPointer(ctlArgsType.CreatePointerType(), - typedNewTuple, 1u); - var controls = builder.Load(this.SharedState.QirArray, controlsPointer); - builder.Store(controls, destControlsPointer); - var destArgsPointer = builder.GetStructElementPointer(ctlArgsType.CreatePointerType(), - typedNewTuple, 2u); - builder.Store(restTuple, destArgsPointer); + // Note that there's a special case if the base specialization only takes a single parameter, + // in which case we don't create the sub-tuple. + if ((parArgsType as IStructType).Members.Count > 2) + { + var ctlArgsType = this.SharedState.CurrentContext.CreateStructType(false, + this.SharedState.QirTupleHeader, this.SharedState.QirArray, this.SharedState.QirTuplePointer); + var ctlArgsPointer = builder.BitCast(func.Parameters[1], ctlArgsType.CreatePointerType()); + var controlsPointer = builder.GetElementPtr(ctlArgsType, ctlArgsPointer, + new Value[] { this.SharedState.CurrentContext.CreateConstant(0L), this.SharedState.CurrentContext.CreateConstant(1) }); + var restPointer = builder.GetElementPtr(ctlArgsType, ctlArgsPointer, + new Value[] { this.SharedState.CurrentContext.CreateConstant(0L), this.SharedState.CurrentContext.CreateConstant(2) }); + var typedRestPointer = builder.BitCast(restPointer, parArgsType.CreatePointerType()); + var restTuple = rebuild.BuildItem(builder, captureType, capturePointer, parArgsType, typedRestPointer); + var size = this.SharedState.ComputeSizeForType(ctlArgsType, builder); + innerArgTuple = builder.Call(this.SharedState.GetRuntimeFunction("tuple_create"), size); + this.SharedState.ScopeMgr.AddValue(innerArgTuple); + var typedNewTuple = builder.BitCast(innerArgTuple, ctlArgsType.CreatePointerType()); + var destControlsPointer = builder.GetElementPtr(ctlArgsType, typedNewTuple, + new Value[] { this.SharedState.CurrentContext.CreateConstant(0L), this.SharedState.CurrentContext.CreateConstant(1) }); + var controls = builder.Load(this.SharedState.QirArray, controlsPointer); + builder.Store(controls, destControlsPointer); + var destArgsPointer = builder.GetElementPtr(ctlArgsType, typedNewTuple, + new Value[] { this.SharedState.CurrentContext.CreateConstant(0L), this.SharedState.CurrentContext.CreateConstant(2) }); + builder.Store(restTuple, destArgsPointer); + } + else + { + // First process the incoming argument. Remember, [0] is the %TupleHeader. + var singleArgType = (parArgsType as IStructType).Members[1]; + var inputArgsType = this.SharedState.CurrentContext.CreateStructType(false, + this.SharedState.QirTupleHeader, this.SharedState.QirArray, singleArgType); + var inputArgsPointer = builder.BitCast(func.Parameters[1], inputArgsType.CreatePointerType()); + var controlsPointer = builder.GetElementPtr(inputArgsType, inputArgsPointer, + new Value[] { this.SharedState.CurrentContext.CreateConstant(0L), this.SharedState.CurrentContext.CreateConstant(1) }); + var restPointer = builder.GetElementPtr(inputArgsType, inputArgsPointer, + new Value[] { this.SharedState.CurrentContext.CreateConstant(0L), this.SharedState.CurrentContext.CreateConstant(2) }); + var restValue = builder.Load(singleArgType, restPointer); + + // OK, now build the full args for the partially-applied callable, other than the controlled qubits + var restTuple = rebuild.BuildItem(builder, captureType, capturePointer, singleArgType, restValue); + // The full args for the inner callable will include the controls + var innerArgType = this.SharedState.CurrentContext.CreateStructType(false, + this.SharedState.QirTupleHeader, this.SharedState.QirArray, restTuple.NativeType); + var size = this.SharedState.ComputeSizeForType(innerArgType, builder); + innerArgTuple = builder.Call(this.SharedState.GetRuntimeFunction("tuple_create"), size); + this.SharedState.ScopeMgr.AddValue(innerArgTuple); + var typedNewTuple = builder.BitCast(innerArgTuple, innerArgType.CreatePointerType()); + var destControlsPointer = builder.GetElementPtr(innerArgType, typedNewTuple, + new Value[] { this.SharedState.CurrentContext.CreateConstant(0L), this.SharedState.CurrentContext.CreateConstant(1) }); + var controls = builder.Load(this.SharedState.QirArray, controlsPointer); + builder.Store(controls, destControlsPointer); + var destArgsPointer = builder.GetElementPtr(innerArgType, typedNewTuple, + new Value[] { this.SharedState.CurrentContext.CreateConstant(0L), this.SharedState.CurrentContext.CreateConstant(2) }); + builder.Store(restTuple, destArgsPointer); + } } else { + var parArgsPointer = builder.BitCast(func.Parameters[1], parArgsType.CreatePointerType()); innerArgTuple = rebuild.BuildItem(builder, captureType, capturePointer, parArgsType, parArgsPointer); } - var innerCallablePtr = builder.GetStructElementPointer(captureType, capturePointer, 1u); + var innerCallablePtr = builder.GetElementPtr(captureType, capturePointer, + new Value[] { this.SharedState.CurrentContext.CreateConstant(0L), this.SharedState.CurrentContext.CreateConstant(1) }); var innerCallable = builder.Load(this.SharedState.QirCallable, innerCallablePtr); // Depending on the specialization, we may have to get a different specialization of the callable var specToCall = GetSpecializedInnerCallable(innerCallable, kind, builder); @@ -751,7 +795,7 @@ IrFunction BuildLiftedSpecialization(string name, QsSpecializationKind kind, ITy QsResolvedTypeKind.Operation pao => pao.Item1.Item1, _ => throw new InvalidOperationException("Partial application of a non-callable value") }; - var parTupleType = paArgTuple.Resolution switch + var partialArgType = paArgTuple.Resolution switch { QsResolvedTypeKind.TupleType pat => this.SharedState.CurrentContext.CreateStructType(false, this.SharedState.QirTupleHeader, pat.Item.Select(this.SharedState.LlvmTypeFromQsharpType).ToArray()), @@ -779,14 +823,16 @@ IrFunction BuildLiftedSpecialization(string name, QsSpecializationKind kind, ITy capTypeList); var cap = this.SharedState.CreateTupleForType(capType); var capture = this.SharedState.CurrentBuilder.BitCast(cap, capType.CreatePointerType()); - var callablePointer = this.SharedState.CurrentBuilder.GetStructElementPointer(capType, capture, (uint)1); + var callablePointer = this.SharedState.CurrentBuilder.GetElementPtr(capType, capture, + new Value[] { this.SharedState.CurrentContext.CreateConstant(0L), this.SharedState.CurrentContext.CreateConstant(1) }); var innerCallable = this.EvaluateSubexpression(method); this.SharedState.CurrentBuilder.Store(innerCallable, callablePointer); this.SharedState.ScopeMgr.RemovePendingValue(innerCallable); //AddRef(method.ResolvedType, innerCallable); for (int n = 0; n < caps.Count; n++) { - var item = this.SharedState.CurrentBuilder.GetStructElementPointer(capType, capture, (uint)n + 2); + var item = this.SharedState.CurrentBuilder.GetElementPtr(capType, capture, + new Value[] { this.SharedState.CurrentContext.CreateConstant(0L), this.SharedState.CurrentContext.CreateConstant(n+2) }); this.SharedState.CurrentBuilder.Store(caps[n].Item1, item); this.SharedState.AddRef(caps[n].Item1); } @@ -826,7 +872,7 @@ IrFunction BuildLiftedSpecialization(string name, QsSpecializationKind kind, ITy if (kinds.Contains(kind)) { specializations[index] = BuildLiftedSpecialization(liftedName, kind, capType, - parTupleType, rebuild); + partialArgType, rebuild); } else { @@ -2030,8 +2076,7 @@ public override ResolvedExpression OnValueTuple(ImmutableArray for (int i = 0; i < vs.Length; i++) { var itemValue = this.EvaluateSubexpression(vs[i]); - var itemPointer = this.SharedState.CurrentBuilder.GetStructElementPointer(tupleType, tuplePointer, - (uint)i + 1); + var itemPointer = this.SharedState.GetTupleElementPointer(tupleType, tuplePointer, i + 1); this.SharedState.CurrentBuilder.Store(itemValue, itemPointer); } diff --git a/src/QsCompiler/QirGenerator/QirStatementKindTransformation.cs b/src/QsCompiler/QirGenerator/QirStatementKindTransformation.cs index 3d7bfe7c64..1e887702be 100644 --- a/src/QsCompiler/QirGenerator/QirStatementKindTransformation.cs +++ b/src/QsCompiler/QirGenerator/QirStatementKindTransformation.cs @@ -427,8 +427,7 @@ void UpdateTuple(ImmutableArray items, Value val) var tuplePointer = this.SharedState.CurrentBuilder.BitCast(val, tupleType.CreatePointerType()); for (int i = 0; i < items.Length; i++) { - var itemValuePtr = this.SharedState.CurrentBuilder.GetStructElementPointer(tupleType, tuplePointer, - (uint)i + 1); + var itemValuePtr = this.SharedState.GetTupleElementPointer(tupleType, tuplePointer, i + 1); var itemValue = this.SharedState.CurrentBuilder.Load(itemTypes[i], itemValuePtr); UpdateItem(items[i], itemValue); } @@ -528,7 +527,6 @@ void BindVariable(string variable, Value value, ResolvedType type) // Bind a structured Value to a tuple of variables (which might contain embedded tuples) void BindTuple(ImmutableArray items, ImmutableArray types, Value val) { - Contract.Assert(items.Length == types.Length, "Tuple to deconstruct doesn't match symbols"); var itemTypes = types.Select(this.SharedState.LlvmTypeFromQsharpType).ToArray(); var tupleType = this.SharedState.CurrentContext.CreateStructType(false, this.SharedState.QirTupleHeader, itemTypes); @@ -542,8 +540,7 @@ void BindTuple(ImmutableArray items, ImmutableArray t } else { - var itemValuePtr = this.SharedState.CurrentBuilder.GetStructElementPointer(tupleType, tuplePointer, - (uint)i + 1); + var itemValuePtr = this.SharedState.GetTupleElementPointer(tupleType, tuplePointer, i + 1); var itemValue = this.SharedState.CurrentBuilder.Load(itemTypes[i], itemValuePtr); BindItem(item, itemValue, types[i]); } @@ -604,7 +601,6 @@ void AllocateVariable(string variable, ResolvedInitializer init) // Generate the allocations for a tuple of variables (or embedded tuples) void AllocateTuple(ImmutableArray items, ImmutableArray types) { - Contract.Assert(items.Length == types.Length, "Initialization list doesn't match symbols"); for (int i = 0; i < items.Length; i++) { AllocateItem(items[i], types[i]); diff --git a/src/QsCompiler/QirGenerator/ScopeManager.cs b/src/QsCompiler/QirGenerator/ScopeManager.cs index d6a4678026..ea427af474 100644 --- a/src/QsCompiler/QirGenerator/ScopeManager.cs +++ b/src/QsCompiler/QirGenerator/ScopeManager.cs @@ -98,6 +98,56 @@ private string GetReleaseFunctionForType(ResolvedType t, bool isQubit) } } + /// + /// Gets the name of the unreference runtime function for a given LLVM type. + /// + /// The LLVM type + /// true if the unreference function should deallocate qubits as well as + /// decrement the reference count + /// The name of the unreference function for this type + private string GetReleaseFunctionForType(ITypeRef t, bool isQubit) + { + if (t == this.sharedState.QirArray) + { + if (isQubit) + { + return "qubit_release_array"; + } + else + { + return "array_unreference"; + } + } + else if (t == this.sharedState.QirQubit) + { + return "qubit_release"; + } + else if (t == this.sharedState.QirResult) + { + return "result_unreference"; + } + else if (t == this.sharedState.QirString) + { + return "string_unreference"; + } + else if (t == this.sharedState.QirBigInt) + { + return "bigint_unreference"; + } + else if ((t == this.sharedState.QirTuplePointer) || this.sharedState.IsTupleType(t)) + { + return "tuple_unreference"; + } + else if (t == this.sharedState.QirCallable) + { + return "callable_unreference"; + } + else + { + return null; + } + } + /// /// Adds a value to the current topmost scope. /// @@ -114,6 +164,20 @@ public void AddValue(Value valueToRelease, ResolvedType valueType) } } + /// + /// Adds a value to the current topmost scope, using its LLVM type to figure out how to + /// dereference the value. + /// + /// The Value to be released + public void AddValue(Value valueToRelease) + { + var releaser = this.GetReleaseFunctionForType(valueToRelease.NativeType, false); + if (releaser != null) + { + this.releaseStack.Peek().Add((valueToRelease, releaser)); + } + } + /// /// Adds a qubit value to the current topmost scope. /// diff --git a/src/QsCompiler/Tests.Compiler/QirTests.fs b/src/QsCompiler/Tests.Compiler/QirTests.fs index 795c65102c..c9a08eb1bf 100644 --- a/src/QsCompiler/Tests.Compiler/QirTests.fs +++ b/src/QsCompiler/Tests.Compiler/QirTests.fs @@ -42,6 +42,10 @@ let private checkOutput name = let actualText = name |> File.ReadAllText Assert.Contains(expectedText, actualText) +let private checkAltOutput name actualText = + let expectedText = ("TestCases","QirTests",name) |> Path.Combine |> File.ReadAllText + Assert.Contains(expectedText, actualText) + let private qirTest target name = clearOutput (name+".ll") [| @@ -80,6 +84,26 @@ let private qirExeTest target name = |> testOne ReturnCode.SUCCESS checkOutput (name+".ll") +let private qirExeMultiTest target name snippets = + [| + "build" + "-o" + "outputFolder" + "--proj" + name + "--build-exe" + "--input" + ("TestCases","QirTests",name+".qs") |> Path.Combine + ("TestCases","QirTests","QirCore.qs") |> Path.Combine + (if target then ("TestCases","QirTests","QirTarget.qs") |> Path.Combine else "") + "--qir" + "--verbosity" + "Diagnostic" + |] + |> testOne ReturnCode.SUCCESS + let actualText = (name+".ll") |> File.ReadAllText + snippets |> List.map (fun s -> checkAltOutput (s+".ll") actualText) + [] let ``QIR using`` () = qirTest false "TestUsing" @@ -136,10 +160,18 @@ let ``QIR bools`` () = let ``QIR bigints`` () = qirTest false "TestBigInts" +[] +let ``QIR controlled partial applications`` () = + qirExeMultiTest true "TestControlled" ["TestControlled1"; "TestControlled2"] + [] let ``QIR entry points`` () = qirExeTest false "TestEntryPoint" +[] +let ``QIR partial applications`` () = + qirExeMultiTest true "TestPartials" ["TestPartials1"; "TestPartials2"; "TestPartials3"] + [] let ``QIR paulis`` () = qirTest false "TestPaulis" diff --git a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestArrayLoop.ll b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestArrayLoop.ll index 89979943ba..0e65741306 100644 --- a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestArrayLoop.ll +++ b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestArrayLoop.ll @@ -2,15 +2,15 @@ define { %TupleHeader, i64, i64 }* @Microsoft__Quantum__Testing__QIR__TestArrayL entry: %0 = call %TupleHeader* @__quantum__rt__tuple_create(i64 ptrtoint ({ %TupleHeader, i64, i64 }* getelementptr ({ %TupleHeader, i64, i64 }, { %TupleHeader, i64, i64 }* null, i32 1) to i64)) %1 = bitcast %TupleHeader* %0 to { %TupleHeader, i64, i64 }* - %2 = getelementptr inbounds { %TupleHeader, i64, i64 }, { %TupleHeader, i64, i64 }* %1, i32 0, i32 1 + %2 = getelementptr { %TupleHeader, i64, i64 }, { %TupleHeader, i64, i64 }* %1, i64 0, i32 1 store i64 0, i64* %2 - %3 = getelementptr inbounds { %TupleHeader, i64, i64 }, { %TupleHeader, i64, i64 }* %1, i32 0, i32 2 + %3 = getelementptr { %TupleHeader, i64, i64 }, { %TupleHeader, i64, i64 }* %1, i64 0, i32 2 store i64 0, i64* %3 - %4 = getelementptr inbounds { %TupleHeader, i64, i64 }, { %TupleHeader, i64, i64 }* %1, i32 0, i32 1 + %4 = getelementptr { %TupleHeader, i64, i64 }, { %TupleHeader, i64, i64 }* %1, i64 0, i32 1 %5 = load i64, i64* %4 %x = alloca i64 store i64 %5, i64* %x - %6 = getelementptr inbounds { %TupleHeader, i64, i64 }, { %TupleHeader, i64, i64 }* %1, i32 0, i32 2 + %6 = getelementptr { %TupleHeader, i64, i64 }, { %TupleHeader, i64, i64 }* %1, i64 0, i32 2 %7 = load i64, i64* %6 %y = alloca i64 store i64 %7, i64* %y @@ -32,9 +32,9 @@ body__1: ; preds = %header__1 %12 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %a, i64 %iter__1) %13 = bitcast i8* %12 to { %TupleHeader, i64, i64 }** %z = load { %TupleHeader, i64, i64 }*, { %TupleHeader, i64, i64 }** %13 - %14 = getelementptr inbounds { %TupleHeader, i64, i64 }, { %TupleHeader, i64, i64 }* %z, i32 0, i32 1 + %14 = getelementptr { %TupleHeader, i64, i64 }, { %TupleHeader, i64, i64 }* %z, i64 0, i32 1 %j = load i64, i64* %14 - %15 = getelementptr inbounds { %TupleHeader, i64, i64 }, { %TupleHeader, i64, i64 }* %z, i32 0, i32 2 + %15 = getelementptr { %TupleHeader, i64, i64 }, { %TupleHeader, i64, i64 }* %z, i64 0, i32 2 %k = load i64, i64* %15 %16 = load i64, i64* %x %17 = add i64 %16, %j @@ -52,12 +52,12 @@ exit__1: ; preds = %header__1 %21 = call %TupleHeader* @__quantum__rt__tuple_create(i64 ptrtoint ({ %TupleHeader, i64, i64 }* getelementptr ({ %TupleHeader, i64, i64 }, { %TupleHeader, i64, i64 }* null, i32 1) to i64)) %22 = bitcast %TupleHeader* %21 to { %TupleHeader, i64, i64 }* %23 = load i64, i64* %x - %24 = getelementptr inbounds { %TupleHeader, i64, i64 }, { %TupleHeader, i64, i64 }* %22, i32 0, i32 1 + %24 = getelementptr { %TupleHeader, i64, i64 }, { %TupleHeader, i64, i64 }* %22, i64 0, i32 1 store i64 %23, i64* %24 %25 = load i64, i64* %y - %26 = getelementptr inbounds { %TupleHeader, i64, i64 }, { %TupleHeader, i64, i64 }* %22, i32 0, i32 2 + %26 = getelementptr { %TupleHeader, i64, i64 }, { %TupleHeader, i64, i64 }* %22, i64 0, i32 2 store i64 %25, i64* %26 %27 = bitcast { %TupleHeader, i64, i64 }* %1 to %TupleHeader* call void @__quantum__rt__tuple_unreference(%TupleHeader* %27) ret { %TupleHeader, i64, i64 }* %22 -} \ No newline at end of file +} diff --git a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestControlled.qs b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestControlled.qs new file mode 100644 index 0000000000..e605d110be --- /dev/null +++ b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestControlled.qs @@ -0,0 +1,70 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// This test extends the basic target with a K gate that implements Controlled. +// THis isn't a real gate, it's just used for testing purposes. +namespace Microsoft.Quantum.Instructions +{ + @Intrinsic("k") + operation PhysK (qb : Qubit, n : Int) : Unit + { + body intrinsic; + } + + @Intrinsic("ck") + operation PhysCtrlK (ctrls : Qubit[], qb : Qubit, n : Int) : Unit + { + body intrinsic; + } +} + +namespace Microsoft.Quantum.Intrinsic +{ + open Microsoft.Quantum.Instructions; + + @Inline() + operation K(qb : Qubit, n : Int) : Unit + is Adj+Ctl { + body (...) + { + PhysK(qb, n); + } + adjoint self; + controlled (ctrls, ...) + { + PhysCtrlK(ctrls, qb, n); + } + } +} + +namespace Microsoft.Quantum.Testing.QIR +{ + open Microsoft.Quantum.Intrinsic; + + @EntryPoint() + operation TestControlled () : Bool + { + let k2 = K(_, 2); + let ck2 = Controlled k2; + let ck1 = K(_, _); + + for (i in 0..100) + { + using ((ctrls, qb) = (Qubit[2], Qubit())) + { + ck2(ctrls, qb); + using (moreCtrls = Qubit[3]) + { + Controlled ck2(moreCtrls, (ctrls, qb)); + Controlled ck1(ctrls, (qb, 1)); + } + if (M(qb) != Zero) + { + return false; + } + } + } + + return true; + } +} diff --git a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestControlled1.ll b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestControlled1.ll new file mode 100644 index 0000000000..45efd2b7b8 --- /dev/null +++ b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestControlled1.ll @@ -0,0 +1,34 @@ +define void @Lifted__PartialApplication__2__ctrl__wrapper(%TupleHeader* %capture-tuple, %TupleHeader* %arg-tuple, %TupleHeader* %result-tuple) { +entry: + %0 = bitcast %TupleHeader* %capture-tuple to { %TupleHeader, %Callable* }* + %1 = bitcast %TupleHeader* %arg-tuple to { %TupleHeader, %Array*, %TupleHeader* }* + %2 = getelementptr { %TupleHeader, %Array*, %TupleHeader* }, { %TupleHeader, %Array*, %TupleHeader* }* %1, i64 0, i32 1 + %3 = getelementptr { %TupleHeader, %Array*, %TupleHeader* }, { %TupleHeader, %Array*, %TupleHeader* }* %1, i64 0, i32 2 + %4 = bitcast %TupleHeader** %3 to { %TupleHeader, %Qubit*, i64 }* + %5 = call %TupleHeader* @__quantum__rt__tuple_create(i64 ptrtoint ({ %TupleHeader, %Qubit*, i64 }* getelementptr ({ %TupleHeader, %Qubit*, i64 }, { %TupleHeader, %Qubit*, i64 }* null, i32 1) to i64)) + %6 = bitcast %TupleHeader* %5 to { %TupleHeader, %Qubit*, i64 }* + %7 = getelementptr { %TupleHeader, %Qubit*, i64 }, { %TupleHeader, %Qubit*, i64 }* %6, i64 0, i32 1 + %8 = getelementptr { %TupleHeader, %Qubit*, i64 }, { %TupleHeader, %Qubit*, i64 }* %4, i64 0, i32 1 + %9 = load %Qubit*, %Qubit** %8 + store %Qubit* %9, %Qubit** %7 + %10 = getelementptr { %TupleHeader, %Qubit*, i64 }, { %TupleHeader, %Qubit*, i64 }* %6, i64 0, i32 2 + %11 = getelementptr { %TupleHeader, %Qubit*, i64 }, { %TupleHeader, %Qubit*, i64 }* %4, i64 0, i32 2 + %12 = load i64, i64* %11 + store i64 %12, i64* %10 + %13 = call %TupleHeader* @__quantum__rt__tuple_create(i64 ptrtoint ({ %TupleHeader, %Array*, %TupleHeader* }* getelementptr ({ %TupleHeader, %Array*, %TupleHeader* }, { %TupleHeader, %Array*, %TupleHeader* }* null, i32 1) to i64)) + %14 = bitcast %TupleHeader* %13 to { %TupleHeader, %Array*, %TupleHeader* }* + %15 = getelementptr { %TupleHeader, %Array*, %TupleHeader* }, { %TupleHeader, %Array*, %TupleHeader* }* %14, i64 0, i32 1 + %16 = load %Array*, %Array** %2 + store %Array* %16, %Array** %15 + %17 = getelementptr { %TupleHeader, %Array*, %TupleHeader* }, { %TupleHeader, %Array*, %TupleHeader* }* %14, i64 0, i32 2 + store %TupleHeader* %5, %TupleHeader** %17 + %18 = getelementptr { %TupleHeader, %Callable* }, { %TupleHeader, %Callable* }* %0, i64 0, i32 1 + %19 = load %Callable*, %Callable** %18 + %20 = call %Callable* @__quantum__rt__callable_copy(%Callable* %19) + call void @__quantum__rt__callable_make_controlled(%Callable* %20) + call void @__quantum__rt__callable_invoke(%Callable* %20, %TupleHeader* %13, %TupleHeader* %result-tuple) + call void @__quantum__rt__tuple_unreference(%TupleHeader* %5) + call void @__quantum__rt__tuple_unreference(%TupleHeader* %13) + call void @__quantum__rt__callable_unreference(%Callable* %20) + ret void +} diff --git a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestControlled2.ll b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestControlled2.ll new file mode 100644 index 0000000000..65e1b55876 --- /dev/null +++ b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestControlled2.ll @@ -0,0 +1,32 @@ +define void @Lifted__PartialApplication__1__ctrl__wrapper(%TupleHeader* %capture-tuple, %TupleHeader* %arg-tuple, %TupleHeader* %result-tuple) { +entry: + %0 = bitcast %TupleHeader* %capture-tuple to { %TupleHeader, %Callable*, i64 }* + %1 = bitcast %TupleHeader* %arg-tuple to { %TupleHeader, %Array*, %Qubit* }* + %2 = getelementptr { %TupleHeader, %Array*, %Qubit* }, { %TupleHeader, %Array*, %Qubit* }* %1, i64 0, i32 1 + %3 = getelementptr { %TupleHeader, %Array*, %Qubit* }, { %TupleHeader, %Array*, %Qubit* }* %1, i64 0, i32 2 + %4 = load %Qubit*, %Qubit** %3 + %5 = call %TupleHeader* @__quantum__rt__tuple_create(i64 ptrtoint ({ %TupleHeader, %Qubit*, i64 }* getelementptr ({ %TupleHeader, %Qubit*, i64 }, { %TupleHeader, %Qubit*, i64 }* null, i32 1) to i64)) + %6 = bitcast %TupleHeader* %5 to { %TupleHeader, %Qubit*, i64 }* + %7 = getelementptr { %TupleHeader, %Qubit*, i64 }, { %TupleHeader, %Qubit*, i64 }* %6, i64 0, i32 1 + store %Qubit* %4, %Qubit** %7 + %8 = getelementptr { %TupleHeader, %Qubit*, i64 }, { %TupleHeader, %Qubit*, i64 }* %6, i64 0, i32 2 + %9 = getelementptr { %TupleHeader, %Callable*, i64 }, { %TupleHeader, %Callable*, i64 }* %0, i64 0, i32 2 + %10 = load i64, i64* %9 + store i64 %10, i64* %8 + %11 = call %TupleHeader* @__quantum__rt__tuple_create(i64 ptrtoint ({ %TupleHeader, %Array*, %TupleHeader* }* getelementptr ({ %TupleHeader, %Array*, %TupleHeader* }, { %TupleHeader, %Array*, %TupleHeader* }* null, i32 1) to i64)) + %12 = bitcast %TupleHeader* %11 to { %TupleHeader, %Array*, %TupleHeader* }* + %13 = getelementptr { %TupleHeader, %Array*, %TupleHeader* }, { %TupleHeader, %Array*, %TupleHeader* }* %12, i64 0, i32 1 + %14 = load %Array*, %Array** %2 + store %Array* %14, %Array** %13 + %15 = getelementptr { %TupleHeader, %Array*, %TupleHeader* }, { %TupleHeader, %Array*, %TupleHeader* }* %12, i64 0, i32 2 + store %TupleHeader* %5, %TupleHeader** %15 + %16 = getelementptr { %TupleHeader, %Callable*, i64 }, { %TupleHeader, %Callable*, i64 }* %0, i64 0, i32 1 + %17 = load %Callable*, %Callable** %16 + %18 = call %Callable* @__quantum__rt__callable_copy(%Callable* %17) + call void @__quantum__rt__callable_make_controlled(%Callable* %18) + call void @__quantum__rt__callable_invoke(%Callable* %18, %TupleHeader* %11, %TupleHeader* %result-tuple) + call void @__quantum__rt__tuple_unreference(%TupleHeader* %5) + call void @__quantum__rt__tuple_unreference(%TupleHeader* %11) + call void @__quantum__rt__callable_unreference(%Callable* %18) + ret void +} diff --git a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestControlled3.ll b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestControlled3.ll new file mode 100644 index 0000000000..7ad30a9d53 --- /dev/null +++ b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestControlled3.ll @@ -0,0 +1,10 @@ +define void @Microsoft__Quantum__Intrinsic__K__ctrl__wrapper(%TupleHeader* %capture-tuple, %TupleHeader* %arg-tuple, %TupleHeader* %result-tuple) { +entry: + %0 = bitcast %TupleHeader* %arg-tuple to { %TupleHeader, %Array*, { %TupleHeader, %Qubit*, i64 }* }* + %1 = getelementptr { %TupleHeader, %Array*, { %TupleHeader, %Qubit*, i64 }* }, { %TupleHeader, %Array*, { %TupleHeader, %Qubit*, i64 }* }* %0, i64 0, i32 1 + %2 = load %Array*, %Array** %1 + %3 = getelementptr { %TupleHeader, %Array*, { %TupleHeader, %Qubit*, i64 }* }, { %TupleHeader, %Array*, { %TupleHeader, %Qubit*, i64 }* }* %0, i64 0, i32 2 + %4 = load { %TupleHeader, %Qubit*, i64 }*, { %TupleHeader, %Qubit*, i64 }** %3 + call void @Microsoft__Quantum__Intrinsic__K__ctrl(%Array* %2, { %TupleHeader, %Qubit*, i64 }* %4) + ret void +} diff --git a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestDeconstruct.ll b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestDeconstruct.ll index 60b8b1fc00..678e060082 100644 --- a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestDeconstruct.ll +++ b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestDeconstruct.ll @@ -1,17 +1,17 @@ define i64 @Microsoft__Quantum__Testing__QIR__TestDeconstruct__body({ %TupleHeader, i64, { %TupleHeader, i64, i64 }* }* %a) { entry: - %0 = getelementptr inbounds { %TupleHeader, i64, { %TupleHeader, i64, i64 }* }, { %TupleHeader, i64, { %TupleHeader, i64, i64 }* }* %a, i32 0, i32 1 + %0 = getelementptr { %TupleHeader, i64, { %TupleHeader, i64, i64 }* }, { %TupleHeader, i64, { %TupleHeader, i64, i64 }* }* %a, i64 0, i32 1 %x = load i64, i64* %0 - %1 = getelementptr inbounds { %TupleHeader, i64, { %TupleHeader, i64, i64 }* }, { %TupleHeader, i64, { %TupleHeader, i64, i64 }* }* %a, i32 0, i32 2 + %1 = getelementptr { %TupleHeader, i64, { %TupleHeader, i64, i64 }* }, { %TupleHeader, i64, { %TupleHeader, i64, i64 }* }* %a, i64 0, i32 2 %y = load { %TupleHeader, i64, i64 }*, { %TupleHeader, i64, i64 }** %1 %b = alloca i64 store i64 3, i64* %b %c = alloca i64 store i64 5, i64* %c - %2 = getelementptr inbounds { %TupleHeader, i64, i64 }, { %TupleHeader, i64, i64 }* %y, i32 0, i32 1 + %2 = getelementptr { %TupleHeader, i64, i64 }, { %TupleHeader, i64, i64 }* %y, i64 0, i32 1 %3 = load i64, i64* %2 store i64 %3, i64* %b - %4 = getelementptr inbounds { %TupleHeader, i64, i64 }, { %TupleHeader, i64, i64 }* %y, i32 0, i32 2 + %4 = getelementptr { %TupleHeader, i64, i64 }, { %TupleHeader, i64, i64 }* %y, i64 0, i32 2 %5 = load i64, i64* %4 store i64 %5, i64* %c %6 = load i64, i64* %b @@ -19,4 +19,4 @@ entry: %8 = mul i64 %6, %7 %9 = add i64 %x, %8 ret i64 %9 -} \ No newline at end of file +} diff --git a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestPartials.qs b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestPartials.qs new file mode 100644 index 0000000000..b4ff079986 --- /dev/null +++ b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestPartials.qs @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Testing.QIR +{ + open Microsoft.Quantum.Intrinsic; + + @EntryPoint() + operation TestPartials () : Bool + { + let rotate = Rz(0.25, _); + let unrotate = Adjoint rotate; + + for (i in 0..100) + { + using (qb = Qubit()) + { + rotate(qb); + unrotate(qb); + if (M(qb) != Zero) + { + return false; + } + } + } + + return true; + } +} diff --git a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestPartials1.ll b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestPartials1.ll new file mode 100644 index 0000000000..a6c532180b --- /dev/null +++ b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestPartials1.ll @@ -0,0 +1,83 @@ +define i1 @Microsoft__Quantum__Testing__QIR__TestPartials__body() #0 { +entry: + %0 = call %TupleHeader* @__quantum__rt__tuple_create(i64 ptrtoint ({ %TupleHeader, %Callable*, double }* getelementptr ({ %TupleHeader, %Callable*, double }, { %TupleHeader, %Callable*, double }* null, i32 1) to i64)) + %1 = bitcast %TupleHeader* %0 to { %TupleHeader, %Callable*, double }* + %2 = getelementptr { %TupleHeader, %Callable*, double }, { %TupleHeader, %Callable*, double }* %1, i64 0, i32 1 + %3 = call %Callable* @__quantum__rt__callable_create([4 x void (%TupleHeader*, %TupleHeader*, %TupleHeader*)*]* @Microsoft__Quantum__Intrinsic__Rz, %TupleHeader* null) + store %Callable* %3, %Callable** %2 + %4 = getelementptr { %TupleHeader, %Callable*, double }, { %TupleHeader, %Callable*, double }* %1, i64 0, i32 2 + store double 2.500000e-01, double* %4 + %rotate = call %Callable* @__quantum__rt__callable_create([4 x void (%TupleHeader*, %TupleHeader*, %TupleHeader*)*]* @PartialApplication__1, %TupleHeader* %0) + %unrotate = call %Callable* @__quantum__rt__callable_copy(%Callable* %rotate) + call void @__quantum__rt__callable_make_adjoint(%Callable* %unrotate) + br label %preheader__1 + +preheader__1: ; preds = %entry + br label %header__1 + +header__1: ; preds = %exiting__1, %preheader__1 + %i = phi i64 [ 0, %preheader__1 ], [ %18, %exiting__1 ] + %5 = icmp sge i64 %i, 100 + %6 = icmp sle i64 %i, 100 + %7 = select i1 true, i1 %6, i1 %5 + br i1 %7, label %body__1, label %exit__1 + +body__1: ; preds = %header__1 + %qb = call %Qubit* @__quantum__rt__qubit_allocate() + %8 = call %TupleHeader* @__quantum__rt__tuple_create(i64 ptrtoint ({ %TupleHeader, %Qubit* }* getelementptr ({ %TupleHeader, %Qubit* }, { %TupleHeader, %Qubit* }* null, i32 1) to i64)) + %9 = bitcast %TupleHeader* %8 to { %TupleHeader, %Qubit* }* + %10 = getelementptr { %TupleHeader, %Qubit* }, { %TupleHeader, %Qubit* }* %9, i64 0, i32 1 + store %Qubit* %qb, %Qubit** %10 + call void @__quantum__rt__callable_invoke(%Callable* %rotate, %TupleHeader* %8, %TupleHeader* null) + %11 = call %TupleHeader* @__quantum__rt__tuple_create(i64 ptrtoint ({ %TupleHeader, %Qubit* }* getelementptr ({ %TupleHeader, %Qubit* }, { %TupleHeader, %Qubit* }* null, i32 1) to i64)) + %12 = bitcast %TupleHeader* %11 to { %TupleHeader, %Qubit* }* + %13 = getelementptr { %TupleHeader, %Qubit* }, { %TupleHeader, %Qubit* }* %12, i64 0, i32 1 + store %Qubit* %qb, %Qubit** %13 + call void @__quantum__rt__callable_invoke(%Callable* %unrotate, %TupleHeader* %11, %TupleHeader* null) + %14 = call %Result* @__quantum__qis__mz(%Qubit* %qb) + %15 = load %Result*, %Result** @ResultZero + %16 = call i1 @__quantum__rt__result_equal(%Result* %14, %Result* %15) + %17 = xor i1 %16, true + br i1 %17, label %then0__1, label %continue__1 + +then0__1: ; preds = %body__1 + call void @__quantum__rt__qubit_release(%Qubit* %qb) + call void @__quantum__rt__callable_unreference(%Callable* %rotate) + call void @__quantum__rt__callable_unreference(%Callable* %unrotate) + ret i1 false + +continue__1: ; preds = %body__1 + call void @__quantum__rt__qubit_release(%Qubit* %qb) + br label %exiting__1 + +exiting__1: ; preds = %continue__1 + %18 = add i64 %i, 1 + br label %header__1 + +exit__1: ; preds = %header__1 + call void @__quantum__rt__callable_unreference(%Callable* %rotate) + call void @__quantum__rt__callable_unreference(%Callable* %unrotate) + ret i1 true +} + +define void @Microsoft__Quantum__Intrinsic__Rz__body__wrapper(%TupleHeader* %capture-tuple, %TupleHeader* %arg-tuple, %TupleHeader* %result-tuple) { +entry: + %0 = bitcast %TupleHeader* %arg-tuple to { %TupleHeader, double, %Qubit* }* + %1 = getelementptr { %TupleHeader, double, %Qubit* }, { %TupleHeader, double, %Qubit* }* %0, i64 0, i32 1 + %2 = load double, double* %1 + %3 = getelementptr { %TupleHeader, double, %Qubit* }, { %TupleHeader, double, %Qubit* }* %0, i64 0, i32 2 + %4 = load %Qubit*, %Qubit** %3 + call void @Microsoft__Quantum__Intrinsic__Rz__body(double %2, %Qubit* %4) + ret void +} + +define void @Microsoft__Quantum__Intrinsic__Rz__adj__wrapper(%TupleHeader* %capture-tuple, %TupleHeader* %arg-tuple, %TupleHeader* %result-tuple) { +entry: + %0 = bitcast %TupleHeader* %arg-tuple to { %TupleHeader, double, %Qubit* }* + %1 = getelementptr { %TupleHeader, double, %Qubit* }, { %TupleHeader, double, %Qubit* }* %0, i64 0, i32 1 + %2 = load double, double* %1 + %3 = getelementptr { %TupleHeader, double, %Qubit* }, { %TupleHeader, double, %Qubit* }* %0, i64 0, i32 2 + %4 = load %Qubit*, %Qubit** %3 + call void @Microsoft__Quantum__Intrinsic__Rz__adj(double %2, %Qubit* %4) + ret void +} diff --git a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestPartials2.ll b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestPartials2.ll new file mode 100644 index 0000000000..c13e1fb142 --- /dev/null +++ b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestPartials2.ll @@ -0,0 +1,20 @@ +define void @Lifted__PartialApplication__1__body__wrapper(%TupleHeader* %capture-tuple, %TupleHeader* %arg-tuple, %TupleHeader* %result-tuple) { +entry: + %0 = bitcast %TupleHeader* %capture-tuple to { %TupleHeader, %Callable*, double }* + %1 = bitcast %TupleHeader* %arg-tuple to { %TupleHeader, %Qubit* }* + %2 = call %TupleHeader* @__quantum__rt__tuple_create(i64 ptrtoint ({ %TupleHeader, double, %Qubit* }* getelementptr ({ %TupleHeader, double, %Qubit* }, { %TupleHeader, double, %Qubit* }* null, i32 1) to i64)) + %3 = bitcast %TupleHeader* %2 to { %TupleHeader, double, %Qubit* }* + %4 = getelementptr { %TupleHeader, double, %Qubit* }, { %TupleHeader, double, %Qubit* }* %3, i64 0, i32 1 + %5 = getelementptr { %TupleHeader, %Callable*, double }, { %TupleHeader, %Callable*, double }* %0, i64 0, i32 2 + %6 = load double, double* %5 + store double %6, double* %4 + %7 = getelementptr { %TupleHeader, double, %Qubit* }, { %TupleHeader, double, %Qubit* }* %3, i64 0, i32 2 + %8 = getelementptr { %TupleHeader, %Qubit* }, { %TupleHeader, %Qubit* }* %1, i64 0, i32 1 + %9 = load %Qubit*, %Qubit** %8 + store %Qubit* %9, %Qubit** %7 + %10 = getelementptr { %TupleHeader, %Callable*, double }, { %TupleHeader, %Callable*, double }* %0, i64 0, i32 1 + %11 = load %Callable*, %Callable** %10 + call void @__quantum__rt__callable_invoke(%Callable* %11, %TupleHeader* %2, %TupleHeader* %result-tuple) + call void @__quantum__rt__tuple_unreference(%TupleHeader* %2) + ret void +} diff --git a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestPartials3.ll b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestPartials3.ll new file mode 100644 index 0000000000..dd032e53fd --- /dev/null +++ b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestPartials3.ll @@ -0,0 +1,23 @@ +define void @Lifted__PartialApplication__1__adj__wrapper(%TupleHeader* %capture-tuple, %TupleHeader* %arg-tuple, %TupleHeader* %result-tuple) { +entry: + %0 = bitcast %TupleHeader* %capture-tuple to { %TupleHeader, %Callable*, double }* + %1 = bitcast %TupleHeader* %arg-tuple to { %TupleHeader, %Qubit* }* + %2 = call %TupleHeader* @__quantum__rt__tuple_create(i64 ptrtoint ({ %TupleHeader, double, %Qubit* }* getelementptr ({ %TupleHeader, double, %Qubit* }, { %TupleHeader, double, %Qubit* }* null, i32 1) to i64)) + %3 = bitcast %TupleHeader* %2 to { %TupleHeader, double, %Qubit* }* + %4 = getelementptr { %TupleHeader, double, %Qubit* }, { %TupleHeader, double, %Qubit* }* %3, i64 0, i32 1 + %5 = getelementptr { %TupleHeader, %Callable*, double }, { %TupleHeader, %Callable*, double }* %0, i64 0, i32 2 + %6 = load double, double* %5 + store double %6, double* %4 + %7 = getelementptr { %TupleHeader, double, %Qubit* }, { %TupleHeader, double, %Qubit* }* %3, i64 0, i32 2 + %8 = getelementptr { %TupleHeader, %Qubit* }, { %TupleHeader, %Qubit* }* %1, i64 0, i32 1 + %9 = load %Qubit*, %Qubit** %8 + store %Qubit* %9, %Qubit** %7 + %10 = getelementptr { %TupleHeader, %Callable*, double }, { %TupleHeader, %Callable*, double }* %0, i64 0, i32 1 + %11 = load %Callable*, %Callable** %10 + %12 = call %Callable* @__quantum__rt__callable_copy(%Callable* %11) + call void @__quantum__rt__callable_make_adjoint(%Callable* %12) + call void @__quantum__rt__callable_invoke(%Callable* %12, %TupleHeader* %2, %TupleHeader* %result-tuple) + call void @__quantum__rt__tuple_unreference(%TupleHeader* %2) + call void @__quantum__rt__callable_unreference(%Callable* %12) + ret void +} diff --git a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestUdt.ll b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestUdt.ll index f3267d446f..02f5f1c7d6 100644 --- a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestUdt.ll +++ b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestUdt.ll @@ -2,11 +2,11 @@ define { %TupleHeader, { %TupleHeader, i2, i64 }*, double }* @Microsoft__Quantum entry: %0 = call %TupleHeader* @__quantum__rt__tuple_create(i64 ptrtoint ({ %TupleHeader, { %TupleHeader, i2, i64 }*, double }* getelementptr ({ %TupleHeader, { %TupleHeader, i2, i64 }*, double }, { %TupleHeader, { %TupleHeader, i2, i64 }*, double }* null, i32 1) to i64)) %1 = bitcast %TupleHeader* %0 to { %TupleHeader, { %TupleHeader, i2, i64 }*, double }* - %2 = getelementptr inbounds { %TupleHeader, { %TupleHeader, i2, i64 }*, double }, { %TupleHeader, { %TupleHeader, i2, i64 }*, double }* %1, i32 0, i32 1 + %2 = getelementptr { %TupleHeader, { %TupleHeader, i2, i64 }*, double }, { %TupleHeader, { %TupleHeader, i2, i64 }*, double }* %1, i64 0, i32 1 store { %TupleHeader, i2, i64 }* %arg0, { %TupleHeader, i2, i64 }** %2 %3 = bitcast { %TupleHeader, i2, i64 }* %arg0 to %TupleHeader* call void @__quantum__rt__tuple_reference(%TupleHeader* %3) - %4 = getelementptr inbounds { %TupleHeader, { %TupleHeader, i2, i64 }*, double }, { %TupleHeader, { %TupleHeader, i2, i64 }*, double }* %1, i32 0, i32 2 + %4 = getelementptr { %TupleHeader, { %TupleHeader, i2, i64 }*, double }, { %TupleHeader, { %TupleHeader, i2, i64 }*, double }* %1, i64 0, i32 2 store double %arg1, double* %4 ret { %TupleHeader, { %TupleHeader, i2, i64 }*, double }* %1 -} \ No newline at end of file +} diff --git a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestUdtAccessor.ll b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestUdtAccessor.ll index 8648e7f7e3..93b44ef6f3 100644 --- a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestUdtAccessor.ll +++ b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestUdtAccessor.ll @@ -3,9 +3,9 @@ entry: %0 = call %TupleHeader* @__quantum__rt__tuple_create(i64 ptrtoint ({ %TupleHeader, i2, i64 }* getelementptr ({ %TupleHeader, i2, i64 }, { %TupleHeader, i2, i64 }* null, i32 1) to i64)) %1 = bitcast %TupleHeader* %0 to { %TupleHeader, i2, i64 }* %2 = load i2, i2* @PauliX - %3 = getelementptr inbounds { %TupleHeader, i2, i64 }, { %TupleHeader, i2, i64 }* %1, i32 0, i32 1 + %3 = getelementptr { %TupleHeader, i2, i64 }, { %TupleHeader, i2, i64 }* %1, i64 0, i32 1 store i2 %2, i2* %3 - %4 = getelementptr inbounds { %TupleHeader, i2, i64 }, { %TupleHeader, i2, i64 }* %1, i32 0, i32 2 + %4 = getelementptr { %TupleHeader, i2, i64 }, { %TupleHeader, i2, i64 }* %1, i64 0, i32 2 store i64 1, i64* %4 %x = call { %TupleHeader, { %TupleHeader, i2, i64 }*, double }* @Microsoft__Quantum__Testing__QIR__TestType__body({ %TupleHeader, i2, i64 }* %1, double 2.000000e+00) %5 = getelementptr { %TupleHeader, { %TupleHeader, i2, i64 }*, double }, { %TupleHeader, { %TupleHeader, i2, i64 }*, double }* %x, i64 0, i32 1 @@ -15,4 +15,4 @@ entry: %8 = bitcast { %TupleHeader, i2, i64 }* %1 to %TupleHeader* call void @__quantum__rt__tuple_unreference(%TupleHeader* %8) ret i64 %y -} \ No newline at end of file +} diff --git a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestUdtConstruction.ll b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestUdtConstruction.ll index f3267d446f..02f5f1c7d6 100644 --- a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestUdtConstruction.ll +++ b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestUdtConstruction.ll @@ -2,11 +2,11 @@ define { %TupleHeader, { %TupleHeader, i2, i64 }*, double }* @Microsoft__Quantum entry: %0 = call %TupleHeader* @__quantum__rt__tuple_create(i64 ptrtoint ({ %TupleHeader, { %TupleHeader, i2, i64 }*, double }* getelementptr ({ %TupleHeader, { %TupleHeader, i2, i64 }*, double }, { %TupleHeader, { %TupleHeader, i2, i64 }*, double }* null, i32 1) to i64)) %1 = bitcast %TupleHeader* %0 to { %TupleHeader, { %TupleHeader, i2, i64 }*, double }* - %2 = getelementptr inbounds { %TupleHeader, { %TupleHeader, i2, i64 }*, double }, { %TupleHeader, { %TupleHeader, i2, i64 }*, double }* %1, i32 0, i32 1 + %2 = getelementptr { %TupleHeader, { %TupleHeader, i2, i64 }*, double }, { %TupleHeader, { %TupleHeader, i2, i64 }*, double }* %1, i64 0, i32 1 store { %TupleHeader, i2, i64 }* %arg0, { %TupleHeader, i2, i64 }** %2 %3 = bitcast { %TupleHeader, i2, i64 }* %arg0 to %TupleHeader* call void @__quantum__rt__tuple_reference(%TupleHeader* %3) - %4 = getelementptr inbounds { %TupleHeader, { %TupleHeader, i2, i64 }*, double }, { %TupleHeader, { %TupleHeader, i2, i64 }*, double }* %1, i32 0, i32 2 + %4 = getelementptr { %TupleHeader, { %TupleHeader, i2, i64 }*, double }, { %TupleHeader, { %TupleHeader, i2, i64 }*, double }* %1, i64 0, i32 2 store double %arg1, double* %4 ret { %TupleHeader, { %TupleHeader, i2, i64 }*, double }* %1 -} \ No newline at end of file +} diff --git a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestUdtUpdate.ll b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestUdtUpdate.ll index a647723892..7570466f90 100644 --- a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestUdtUpdate.ll +++ b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestUdtUpdate.ll @@ -2,9 +2,9 @@ define { %TupleHeader, { %TupleHeader, double, i64 }*, i64 }* @Microsoft__Quantu entry: %0 = call %TupleHeader* @__quantum__rt__tuple_create(i64 ptrtoint ({ %TupleHeader, double, i64 }* getelementptr ({ %TupleHeader, double, i64 }, { %TupleHeader, double, i64 }* null, i32 1) to i64)) %1 = bitcast %TupleHeader* %0 to { %TupleHeader, double, i64 }* - %2 = getelementptr inbounds { %TupleHeader, double, i64 }, { %TupleHeader, double, i64 }* %1, i32 0, i32 1 + %2 = getelementptr { %TupleHeader, double, i64 }, { %TupleHeader, double, i64 }* %1, i64 0, i32 1 store double 1.000000e+00, double* %2 - %3 = getelementptr inbounds { %TupleHeader, double, i64 }, { %TupleHeader, double, i64 }* %1, i32 0, i32 2 + %3 = getelementptr { %TupleHeader, double, i64 }, { %TupleHeader, double, i64 }* %1, i64 0, i32 2 store i64 %a, i64* %3 %4 = call { %TupleHeader, { %TupleHeader, double, i64 }*, i64 }* @Microsoft__Quantum__Testing__QIR__TestType__body({ %TupleHeader, double, i64 }* %1, i64 %b) %x = alloca { %TupleHeader, { %TupleHeader, double, i64 }*, i64 }* @@ -12,23 +12,23 @@ entry: %5 = load { %TupleHeader, { %TupleHeader, double, i64 }*, i64 }*, { %TupleHeader, { %TupleHeader, double, i64 }*, i64 }** %x %6 = call %TupleHeader* @__quantum__rt__tuple_create(i64 ptrtoint ({ %TupleHeader, { %TupleHeader, double, i64 }*, i64 }* getelementptr ({ %TupleHeader, { %TupleHeader, double, i64 }*, i64 }, { %TupleHeader, { %TupleHeader, double, i64 }*, i64 }* null, i32 1) to i64)) %7 = bitcast %TupleHeader* %6 to { %TupleHeader, { %TupleHeader, double, i64 }*, i64 }* - %8 = getelementptr inbounds { %TupleHeader, { %TupleHeader, double, i64 }*, i64 }, { %TupleHeader, { %TupleHeader, double, i64 }*, i64 }* %5, i32 0, i32 1 + %8 = getelementptr { %TupleHeader, { %TupleHeader, double, i64 }*, i64 }, { %TupleHeader, { %TupleHeader, double, i64 }*, i64 }* %5, i64 0, i32 1 %9 = load { %TupleHeader, double, i64 }*, { %TupleHeader, double, i64 }** %8 %10 = call %TupleHeader* @__quantum__rt__tuple_create(i64 ptrtoint ({ %TupleHeader, double, i64 }* getelementptr ({ %TupleHeader, double, i64 }, { %TupleHeader, double, i64 }* null, i32 1) to i64)) %11 = bitcast %TupleHeader* %10 to { %TupleHeader, double, i64 }* - %12 = getelementptr inbounds { %TupleHeader, double, i64 }, { %TupleHeader, double, i64 }* %9, i32 0, i32 1 + %12 = getelementptr { %TupleHeader, double, i64 }, { %TupleHeader, double, i64 }* %9, i64 0, i32 1 %13 = load double, double* %12 - %14 = getelementptr inbounds { %TupleHeader, double, i64 }, { %TupleHeader, double, i64 }* %11, i32 0, i32 1 + %14 = getelementptr { %TupleHeader, double, i64 }, { %TupleHeader, double, i64 }* %11, i64 0, i32 1 store double %13, double* %14 - %15 = getelementptr inbounds { %TupleHeader, double, i64 }, { %TupleHeader, double, i64 }* %9, i32 0, i32 2 + %15 = getelementptr { %TupleHeader, double, i64 }, { %TupleHeader, double, i64 }* %9, i64 0, i32 2 %16 = load i64, i64* %15 - %17 = getelementptr inbounds { %TupleHeader, double, i64 }, { %TupleHeader, double, i64 }* %11, i32 0, i32 2 + %17 = getelementptr { %TupleHeader, double, i64 }, { %TupleHeader, double, i64 }* %11, i64 0, i32 2 store i64 %16, i64* %17 - %18 = getelementptr inbounds { %TupleHeader, { %TupleHeader, double, i64 }*, i64 }, { %TupleHeader, { %TupleHeader, double, i64 }*, i64 }* %7, i32 0, i32 1 + %18 = getelementptr { %TupleHeader, { %TupleHeader, double, i64 }*, i64 }, { %TupleHeader, { %TupleHeader, double, i64 }*, i64 }* %7, i64 0, i32 1 store { %TupleHeader, double, i64 }* %11, { %TupleHeader, double, i64 }** %18 - %19 = getelementptr inbounds { %TupleHeader, { %TupleHeader, double, i64 }*, i64 }, { %TupleHeader, { %TupleHeader, double, i64 }*, i64 }* %5, i32 0, i32 2 + %19 = getelementptr { %TupleHeader, { %TupleHeader, double, i64 }*, i64 }, { %TupleHeader, { %TupleHeader, double, i64 }*, i64 }* %5, i64 0, i32 2 %20 = load i64, i64* %19 - %21 = getelementptr inbounds { %TupleHeader, { %TupleHeader, double, i64 }*, i64 }, { %TupleHeader, { %TupleHeader, double, i64 }*, i64 }* %7, i32 0, i32 2 + %21 = getelementptr { %TupleHeader, { %TupleHeader, double, i64 }*, i64 }, { %TupleHeader, { %TupleHeader, double, i64 }*, i64 }* %7, i64 0, i32 2 store i64 %20, i64* %21 %22 = getelementptr { %TupleHeader, { %TupleHeader, double, i64 }*, i64 }, { %TupleHeader, { %TupleHeader, double, i64 }*, i64 }* %7, i64 0, i32 1 %23 = load { %TupleHeader, double, i64 }*, { %TupleHeader, double, i64 }** %22 @@ -41,4 +41,4 @@ entry: %27 = bitcast { %TupleHeader, double, i64 }* %1 to %TupleHeader* call void @__quantum__rt__tuple_unreference(%TupleHeader* %27) ret { %TupleHeader, { %TupleHeader, double, i64 }*, i64 }* %26 -} \ No newline at end of file +} diff --git a/src/QsCompiler/Tests.Compiler/Tests.Compiler.fsproj b/src/QsCompiler/Tests.Compiler/Tests.Compiler.fsproj index 9f67c10da3..69b872e0de 100644 --- a/src/QsCompiler/Tests.Compiler/Tests.Compiler.fsproj +++ b/src/QsCompiler/Tests.Compiler/Tests.Compiler.fsproj @@ -1,330 +1,351 @@ - - - - - netcoreapp3.1 - false - Tests.Microsoft.Quantum.QsCompiler - Library - - - - TRACE;DEBUG - - - - - - - - - - - + + + + + netcoreapp3.1 + false + Tests.Microsoft.Quantum.QsCompiler + Library + + + + TRACE;DEBUG + + + + + + + + + + + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + PreserveNewest - - - - - - - - - - - - - - - - - - - - - - - - - - - - - all - runtime; build; native; contentfiles; analyzers - - - - - - - - false - - - - - - - - - - - $(MSBuildThisFileDirectory)..\TestTargets\Simulation\Example\bin\$(Configuration)\netcoreapp3.1\Example.dll - $(MSBuildThisFileDirectory)..\TestTargets\Libraries\Library1\bin\$(Configuration)\netcoreapp3.1\Library1.dll - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers + + + + + + + + false + + + + + + + + + + + $(MSBuildThisFileDirectory)..\TestTargets\Simulation\Example\bin\$(Configuration)\netcoreapp3.1\Example.dll + $(MSBuildThisFileDirectory)..\TestTargets\Libraries\Library1\bin\$(Configuration)\netcoreapp3.1\Library1.dll + + + + +