diff --git a/src/QsCompiler/Core/Dependencies.fs b/src/QsCompiler/Core/Dependencies.fs index 18acf94ab6..41bd271469 100644 --- a/src/QsCompiler/Core/Dependencies.fs +++ b/src/QsCompiler/Core/Dependencies.fs @@ -28,6 +28,7 @@ type BuiltIn = static member ClassicallyControlledNamespace = "Microsoft.Quantum.ClassicalControl" static member CoreNamespace = "Microsoft.Quantum.Core" static member DiagnosticsNamespace = "Microsoft.Quantum.Diagnostics" + static member LlvmNamespace = "Microsoft.Quantum.Llvm" static member IntrinsicNamespace = "Microsoft.Quantum.Intrinsic" static member StandardArrayNamespace = "Microsoft.Quantum.Arrays" static member TargetingNamespace = "Microsoft.Quantum.Targeting" @@ -88,6 +89,8 @@ type BuiltIn = BuiltIn.EnableTestingViaName BuiltIn.DumpMachine BuiltIn.DumpRegister + // in Microsoft.Quantum.Llvm + BuiltIn.ReadCycleCounter // in Microsoft.Quantum.Canon BuiltIn.NoOp // in Microsoft.Quantum.Convert @@ -250,6 +253,14 @@ type BuiltIn = Kind = Function(TypeParameters = ImmutableArray.Create "T") } + // dependencies in Microsoft.Quantum.Llvm + + static member ReadCycleCounter = + { + FullName = { Name = "ReadCycleCounter"; Namespace = BuiltIn.LlvmNamespace } + Kind = Operation(TypeParameters = ImmutableArray.Empty, IsSelfAdjoint = false) + } + // dependencies in Microsoft.Quantum.Canon static member NoOp = diff --git a/src/QsCompiler/QirGeneration/QIR/Functions.cs b/src/QsCompiler/QirGeneration/QIR/Functions.cs index 83724384bd..703be51de9 100644 --- a/src/QsCompiler/QirGeneration/QIR/Functions.cs +++ b/src/QsCompiler/QirGeneration/QIR/Functions.cs @@ -61,6 +61,7 @@ public Functions(GenerationContext sharedState) optBuiltIn.Add(QsCompiler.BuiltIn.RangeReverse.FullName, this.RangeReverse); builtIn.Add(QsCompiler.BuiltIn.Message.FullName, this.Message); builtIn.Add(QsCompiler.BuiltIn.Truncate.FullName, this.DoubleAsInt); // This redundancy needs to be eliminated in the Q# libraries. + builtIn.Add(QsCompiler.BuiltIn.ReadCycleCounter.FullName, this.ReadCycleCounter); builtIn.Add(QsCompiler.BuiltIn.DumpMachine.FullName, this.DumpMachine); builtIn.Add(QsCompiler.BuiltIn.DumpRegister.FullName, this.DumpRegister); optBuiltIn.Add(QsCompiler.BuiltIn.DumpRegister.FullName, this.DumpRegister); @@ -279,6 +280,13 @@ private IValue Message(IValue arg) return this.sharedState.Values.Unit; } + private IValue ReadCycleCounter(IValue arg) + { + var func = this.sharedState.Module.GetIntrinsicDeclaration("llvm.readcyclecounter"); + var call = this.sharedState.CurrentBuilder.Call(func); + return this.sharedState.Values.FromSimpleValue(call, Int); + } + private IValue DumpMachine(IValue arg) { var value = arg.Value; diff --git a/src/QsCompiler/QirGeneration/Subtransformations/ExpressionKindTransformation.cs b/src/QsCompiler/QirGeneration/Subtransformations/ExpressionKindTransformation.cs index c11126c627..7c255c5b84 100644 --- a/src/QsCompiler/QirGeneration/Subtransformations/ExpressionKindTransformation.cs +++ b/src/QsCompiler/QirGeneration/Subtransformations/ExpressionKindTransformation.cs @@ -860,6 +860,12 @@ IValue InlineSpecialization(QsSpecialization spec, TypedExpression arg) { throw new InvalidOperationException("Q# declaration for global callable not found"); } + else if (kind == QsSpecializationKind.QsBody // adjointable and controllable operations are not evaluated by the runtime + && this.SharedState.Functions.TryEvaluate(callableName, arg, out var evaluated)) + { + // deal with recognized callables provided by the runtime + return evaluated; + } else if (NameGeneration.TryGetTargetInstructionName(callable, out var instructionName)) { // deal with functions that are part of the target specific instruction set @@ -1480,14 +1486,9 @@ public override ResolvedExpressionKind OnFunctionCall(TypedExpression method, Ty // deal with local values; i.e. callables e.g. from partial applications or stored in local variables value = this.InvokeLocalCallable(method, arg); } - else if (this.SharedState.Functions.TryEvaluate(callableName, arg, out var evaluated)) - { - // deal with recognized runtime functions - value = evaluated; - } else { - // deal with other global callables + // deal with global callables value = this.InvokeGlobalCallable(callableName, QsSpecializationKind.QsBody, arg); } diff --git a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestBuiltInIntrinsics.qs b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestBuiltInIntrinsics.qs index 828814b513..07386a6338 100644 --- a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestBuiltInIntrinsics.qs +++ b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestBuiltInIntrinsics.qs @@ -4,6 +4,7 @@ namespace Microsoft.Quantum.Testing.QIR { open Microsoft.Quantum.Intrinsic; open Microsoft.Quantum.Diagnostics; + open Microsoft.Quantum.Llvm; newtype Options = ( SimpleMessage: (String -> Unit), @@ -22,7 +23,7 @@ namespace Microsoft.Quantum.Testing.QIR { } @EntryPoint() - operation TestBuiltInIntrinsics() : Unit { + operation TestBuiltInIntrinsics() : Int { let options = DefaultOptions() w/ SimpleMessage <- Message w/ DumpToFile <- DumpMachine @@ -31,6 +32,7 @@ namespace Microsoft.Quantum.Testing.QIR { options::SimpleMessage("Hello"); options::DumpToFile("pathToFile"); options::DumpToConsole(); + return ReadCycleCounter(); } } @@ -47,3 +49,10 @@ namespace Microsoft.Quantum.Diagnostics { body intrinsic; } } + +namespace Microsoft.Quantum.Llvm { + + operation ReadCycleCounter() : Int { + body intrinsic; + } +} diff --git a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestBuiltInIntrinsics1.ll b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestBuiltInIntrinsics1.ll index 009ddc3540..ec324c1359 100644 --- a/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestBuiltInIntrinsics1.ll +++ b/src/QsCompiler/Tests.Compiler/TestCases/QirTests/TestBuiltInIntrinsics1.ll @@ -1,4 +1,4 @@ -define internal void @Microsoft__Quantum__Testing__QIR__TestBuiltInIntrinsics__body() { +define internal i64 @Microsoft__Quantum__Testing__QIR__TestBuiltInIntrinsics__body() { entry: %0 = call { %Callable*, %Callable*, %Callable* }* @Microsoft__Quantum__Testing__QIR__DefaultOptions__body() %1 = bitcast { %Callable*, %Callable*, %Callable* }* %0 to %Tuple* @@ -50,6 +50,7 @@ entry: store %String* %24, %String** %27, align 8 call void @__quantum__rt__callable_invoke(%Callable* %19, %Tuple* %25, %Tuple* null) call void @__quantum__rt__callable_invoke(%Callable* %14, %Tuple* null, %Tuple* null) + %28 = call i64 @llvm.readcyclecounter() call void @__quantum__rt__capture_update_alias_count(%Callable* %17, i32 -1) call void @__quantum__rt__callable_update_alias_count(%Callable* %17, i32 -1) call void @__quantum__rt__capture_update_alias_count(%Callable* %19, i32 -1) @@ -71,5 +72,5 @@ entry: call void @__quantum__rt__tuple_update_reference_count(%Tuple* %21, i32 -1) call void @__quantum__rt__string_update_reference_count(%String* %24, i32 -1) call void @__quantum__rt__tuple_update_reference_count(%Tuple* %25, i32 -1) - ret void + ret i64 %28 }