Skip to content

Commit b9a5957

Browse files
authored
Merge 920b49d into 5763700
2 parents 5763700 + 920b49d commit b9a5957

File tree

5 files changed

+189
-4
lines changed

5 files changed

+189
-4
lines changed

compiler/qsc_data_structures/src/functors.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::{
88
};
99

1010
/// A functor application.
11-
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
11+
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash)]
1212
pub struct FunctorApp {
1313
/// An invocation is either adjoint or not, with each successive use of `Adjoint` functor switching
1414
/// between the two, so a bool is sufficient to track.

compiler/qsc_eval/src/lib.rs

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ use qsc_fir::fir::{
4343
use qsc_fir::ty::Ty;
4444
use qsc_lowerer::map_fir_package_to_hir;
4545
use rand::{rngs::StdRng, SeedableRng};
46-
use rustc_hash::FxHashSet;
46+
use rustc_hash::{FxHashMap, FxHashSet};
4747
use std::ops;
4848
use std::{
4949
cell::RefCell,
@@ -449,6 +449,7 @@ pub struct State {
449449
call_stack: CallStack,
450450
current_span: Span,
451451
rng: RefCell<StdRng>,
452+
call_counts: FxHashMap<(StoreItemId, FunctorApp), i64>,
452453
}
453454

454455
impl State {
@@ -473,6 +474,7 @@ impl State {
473474
call_stack: CallStack::default(),
474475
current_span: Span::default(),
475476
rng,
477+
call_counts: FxHashMap::default(),
476478
}
477479
}
478480

@@ -974,9 +976,20 @@ impl State {
974976

975977
let spec = spec_from_functor_app(functor);
976978
match &callee.implementation {
979+
CallableImpl::Intrinsic if is_counting_call(&callee.name.name) => {
980+
self.push_frame(Vec::new().into(), callee_id, functor);
981+
982+
let val = self.counting_call(&callee.name.name, arg);
983+
984+
self.set_val_register(val);
985+
self.leave_frame();
986+
Ok(())
987+
}
977988
CallableImpl::Intrinsic => {
978989
self.push_frame(Vec::new().into(), callee_id, functor);
979990

991+
self.increment_call_count(callee_id, functor);
992+
980993
let name = &callee.name.name;
981994
let val = intrinsic::call(
982995
name,
@@ -1007,6 +1020,7 @@ impl State {
10071020
.expect("missing specialization should be a compilation error");
10081021
self.push_frame(spec_decl.exec_graph.clone(), callee_id, functor);
10091022
self.push_scope(env);
1023+
self.increment_call_count(callee_id, functor);
10101024

10111025
self.bind_args_for_spec(
10121026
env,
@@ -1448,6 +1462,31 @@ impl State {
14481462
span,
14491463
}
14501464
}
1465+
1466+
fn counting_call(&mut self, name: &str, arg: Value) -> Value {
1467+
let callable = if let Value::Closure(closure) = arg {
1468+
(closure.id, closure.functor)
1469+
} else {
1470+
arg.unwrap_global()
1471+
};
1472+
match name {
1473+
"StartCountingOperation" | "StartCountingFunction" => {
1474+
self.call_counts.insert(callable, 0);
1475+
Value::unit()
1476+
}
1477+
"StopCountingOperation" | "StopCountingFunction" => {
1478+
let count = self.call_counts.remove(&callable).unwrap_or(-1);
1479+
Value::Int(count)
1480+
}
1481+
_ => panic!("unknown counting call"),
1482+
}
1483+
}
1484+
1485+
fn increment_call_count(&mut self, callee_id: StoreItemId, functor: FunctorApp) {
1486+
if let Some(count) = self.call_counts.get_mut(&(callee_id, functor)) {
1487+
*count += 1;
1488+
}
1489+
}
14511490
}
14521491

14531492
pub fn are_ctls_unique(ctls: &[Value], tup: &Value) -> bool {
@@ -1937,3 +1976,13 @@ fn is_updatable_in_place(env: &Env, expr: &Expr) -> (bool, bool) {
19371976
_ => (false, false),
19381977
}
19391978
}
1979+
1980+
fn is_counting_call(name: &str) -> bool {
1981+
matches!(
1982+
name,
1983+
"StartCountingOperation"
1984+
| "StopCountingOperation"
1985+
| "StartCountingFunction"
1986+
| "StopCountingFunction"
1987+
)
1988+
}

compiler/qsc_fir/src/fir.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,7 @@ pub enum Global<'a> {
324324
}
325325

326326
/// A unique identifier for an item within a package store.
327-
#[derive(Clone, Copy, Debug, PartialEq)]
327+
#[derive(Clone, Copy, Debug, PartialEq, Hash, Eq)]
328328
pub struct StoreItemId {
329329
/// The package ID.
330330
pub package: PackageId,

library/qs_source/src/std/diagnostics.qs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,5 +149,25 @@ namespace Microsoft.Quantum.Diagnostics {
149149
areEqual
150150
}
151151

152-
export DumpMachine, DumpRegister, CheckZero, CheckAllZero, Fact, CheckOperationsAreEqual;
152+
@Config(Unrestricted)
153+
operation StartCountingOperation<'In, 'Out>(callable : 'In => 'Out) : Unit {
154+
body intrinsic;
155+
}
156+
157+
@Config(Unrestricted)
158+
operation StopCountingOperation<'In, 'Out>(callable : 'In => 'Out) : Int {
159+
body intrinsic;
160+
}
161+
162+
@Config(Unrestricted)
163+
operation StartCountingFunction<'In, 'Out>(callable : 'In -> 'Out) : Unit {
164+
body intrinsic;
165+
}
166+
167+
@Config(Unrestricted)
168+
operation StopCountingFunction<'In, 'Out>(callable : 'In -> 'Out) : Int {
169+
body intrinsic;
170+
}
171+
172+
export DumpMachine, DumpRegister, CheckZero, CheckAllZero, Fact, CheckOperationsAreEqual, StartCountingOperation, StopCountingOperation, StartCountingFunction, StopCountingFunction;
153173
}

library/src/tests/diagnostics.rs

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,119 @@ fn check_operations_are_equal() {
4040
),
4141
);
4242
}
43+
44+
#[test]
45+
fn check_start_stop_counting_operation_called_3_times() {
46+
test_expression(
47+
"{
48+
import Microsoft.Quantum.Diagnostics.StartCountingOperation;
49+
import Microsoft.Quantum.Diagnostics.StopCountingOperation;
50+
51+
operation op1() : Unit {}
52+
operation op2() : Unit { op1(); }
53+
StartCountingOperation(op1);
54+
StartCountingOperation(op2);
55+
op1(); op1(); op2();
56+
(StopCountingOperation(op1), StopCountingOperation(op2))
57+
}",
58+
&Value::Tuple([Value::Int(3), Value::Int(1)].into()),
59+
);
60+
}
61+
62+
#[test]
63+
fn check_start_stop_counting_operation_called_0_times() {
64+
test_expression(
65+
"{
66+
import Microsoft.Quantum.Diagnostics.StartCountingOperation;
67+
import Microsoft.Quantum.Diagnostics.StopCountingOperation;
68+
69+
operation op1() : Unit {}
70+
operation op2() : Unit { op1(); }
71+
StartCountingOperation(op1);
72+
StartCountingOperation(op2);
73+
(StopCountingOperation(op1), StopCountingOperation(op2))
74+
}",
75+
&Value::Tuple([Value::Int(0), Value::Int(0)].into()),
76+
);
77+
}
78+
79+
#[test]
80+
fn check_stop_counting_operation_without_start() {
81+
test_expression(
82+
"{
83+
import Microsoft.Quantum.Diagnostics.StopCountingOperation;
84+
85+
operation op1() : Unit {}
86+
StopCountingOperation(op1)
87+
}",
88+
&Value::Int(-1),
89+
);
90+
}
91+
92+
#[test]
93+
fn check_counting_operation_differentiates_between_body_adj_ctl() {
94+
test_expression(
95+
"{
96+
import Microsoft.Quantum.Diagnostics.StartCountingOperation;
97+
import Microsoft.Quantum.Diagnostics.StopCountingOperation;
98+
99+
operation op1() : Unit is Adj + Ctl {}
100+
StartCountingOperation(op1);
101+
StartCountingOperation(Adjoint op1);
102+
StartCountingOperation(Controlled op1);
103+
op1();
104+
Adjoint op1(); Adjoint op1();
105+
Controlled op1([], ()); Controlled op1([], ()); Controlled op1([], ());
106+
(StopCountingOperation(op1), StopCountingOperation(Adjoint op1), StopCountingOperation(Controlled op1))
107+
}",
108+
&Value::Tuple([Value::Int(1), Value::Int(2), Value::Int(3)].into()),
109+
);
110+
}
111+
112+
#[test]
113+
fn check_start_stop_counting_function_called_3_times() {
114+
test_expression(
115+
"{
116+
import Microsoft.Quantum.Diagnostics.StartCountingFunction;
117+
import Microsoft.Quantum.Diagnostics.StopCountingFunction;
118+
119+
function f1() : Unit {}
120+
function f2() : Unit { f1(); }
121+
StartCountingFunction(f1);
122+
StartCountingFunction(f2);
123+
f1(); f1(); f2();
124+
(StopCountingFunction(f1), StopCountingFunction(f2))
125+
}",
126+
&Value::Tuple([Value::Int(3), Value::Int(1)].into()),
127+
);
128+
}
129+
130+
#[test]
131+
fn check_start_stop_counting_function_called_0_times() {
132+
test_expression(
133+
"{
134+
import Microsoft.Quantum.Diagnostics.StartCountingFunction;
135+
import Microsoft.Quantum.Diagnostics.StopCountingFunction;
136+
137+
function f1() : Unit {}
138+
function f2() : Unit { f1(); }
139+
StartCountingFunction(f1);
140+
StartCountingFunction(f2);
141+
(StopCountingFunction(f1), StopCountingFunction(f2))
142+
}",
143+
&Value::Tuple([Value::Int(0), Value::Int(0)].into()),
144+
);
145+
}
146+
147+
#[test]
148+
fn check_stop_counting_function_without_start() {
149+
test_expression(
150+
"{
151+
import Microsoft.Quantum.Diagnostics.StopCountingFunction;
152+
153+
function f1() : Unit {}
154+
StopCountingFunction(f1)
155+
}",
156+
&Value::Int(-1),
157+
);
158+
}

0 commit comments

Comments
 (0)