Skip to content

Commit 8866a89

Browse files
committed
Ensure interpreter supports global qubits
1 parent 94264e4 commit 8866a89

File tree

8 files changed

+102
-18
lines changed

8 files changed

+102
-18
lines changed

compiler/qsc/src/interpret/stateful/tests.rs

+17
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,23 @@ mod given_interpreter {
222222
);
223223
is_unit_with_output(&result, &output, "before\nafter");
224224
}
225+
226+
#[test]
227+
fn global_qubits() {
228+
let mut interpreter = get_interpreter();
229+
let (result, output) = line(&mut interpreter, "open Microsoft.Quantum.Diagnostics;");
230+
is_only_value(&result, &output, &Value::unit());
231+
let (result, output) = line(&mut interpreter, "DumpMachine()");
232+
is_unit_with_output(&result, &output, "STATE:\n|0⟩: 1+0i");
233+
let (result, output) = line(&mut interpreter, "use (q0, qs) = (Qubit(), Qubit[3]);");
234+
is_only_value(&result, &output, &Value::unit());
235+
let (result, output) = line(&mut interpreter, "DumpMachine()");
236+
is_unit_with_output(&result, &output, "STATE:\n|0000⟩: 1+0i");
237+
let (result, output) = line(&mut interpreter, "X(q0); X(qs[1]);");
238+
is_only_value(&result, &output, &Value::unit());
239+
let (result, output) = line(&mut interpreter, "DumpMachine()");
240+
is_unit_with_output(&result, &output, "STATE:\n|0101⟩: 1+0i");
241+
}
225242
}
226243

227244
#[cfg(test)]

compiler/qsc_eval/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,7 @@ impl<'a, G: GlobalLookup<'a>> State<'a, G> {
663663
fn handle_stmt(&mut self, stmt: &'a Stmt) {
664664
match &stmt.kind {
665665
StmtKind::Expr(expr) => self.push_expr(expr),
666+
StmtKind::Err => panic!("err stmt should not be present during evaluation"),
666667
StmtKind::Item(..) => self.push_val(Value::unit()),
667668
StmtKind::Local(mutability, pat, expr) => {
668669
self.push_cont(Cont::Bind(pat, *mutability));

compiler/qsc_hir/src/hir.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -541,10 +541,13 @@ impl Display for Stmt {
541541
}
542542

543543
/// A statement kind.
544-
#[derive(Clone, Debug, PartialEq)]
544+
#[derive(Clone, Debug, Default, PartialEq)]
545545
pub enum StmtKind {
546546
/// An expression without a trailing semicolon.
547547
Expr(Expr),
548+
/// Default, empty statement case.
549+
#[default]
550+
Err,
548551
/// An item.
549552
Item(LocalItemId),
550553
/// A let or mutable binding: `let a = b;` or `mutable x = b;`.
@@ -560,6 +563,7 @@ impl Display for StmtKind {
560563
let mut indent = set_indentation(indented(f), 0);
561564
match self {
562565
StmtKind::Expr(e) => write!(indent, "Expr: {e}")?,
566+
StmtKind::Err => panic!("statement kind Err should not be displayed"),
563567
StmtKind::Item(item) => write!(indent, "Item: {item}")?,
564568
StmtKind::Local(m, lhs, rhs) => {
565569
write!(indent, "Local ({m:?}):")?;

compiler/qsc_hir/src/mut_visit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ pub fn walk_stmt(vis: &mut impl MutVisitor, stmt: &mut Stmt) {
116116
vis.visit_span(&mut stmt.span);
117117

118118
match &mut stmt.kind {
119-
StmtKind::Item(_) => {}
119+
StmtKind::Item(_) | StmtKind::Err => {}
120120
StmtKind::Expr(expr) | StmtKind::Semi(expr) => vis.visit_expr(expr),
121121
StmtKind::Local(_, pat, value) => {
122122
vis.visit_pat(pat);

compiler/qsc_hir/src/visit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ pub fn walk_block<'a>(vis: &mut impl Visitor<'a>, block: &'a Block) {
100100

101101
pub fn walk_stmt<'a>(vis: &mut impl Visitor<'a>, stmt: &'a Stmt) {
102102
match &stmt.kind {
103-
StmtKind::Item(_) => {}
103+
StmtKind::Item(_) | StmtKind::Err => {}
104104
StmtKind::Expr(expr) | StmtKind::Semi(expr) => vis.visit_expr(expr),
105105
StmtKind::Local(_, pat, value) => {
106106
vis.visit_pat(pat);

compiler/qsc_passes/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ pub fn run_core_passes(core: &mut CompileUnit) {
5959
assigner: &mut core.assigner,
6060
}
6161
.visit_package(&mut core.package);
62+
ReplaceQubitAllocation::new(&table, &mut core.assigner).visit_package(&mut core.package);
6263
}
6364

6465
pub fn run_default_passes_for_fragment(

compiler/qsc_passes/src/logic_sep.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ impl<'a> Visitor<'a> for SepCheck {
6969
let mut has_inner_op_call = false;
7070
for stmt in &block.stmts {
7171
let has_op_call = match &stmt.kind {
72-
StmtKind::Item(_) => false,
72+
StmtKind::Item(_) | StmtKind::Err => false,
7373

7474
StmtKind::Local(..) | StmtKind::Qubit(_, _, _, None) => {
7575
self.op_call_allowed = false;

compiler/qsc_passes/src/replace_qubit_allocation.rs

+75-14
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,63 @@ impl MutVisitor for ReplaceQubitAllocation<'_> {
336336
_ => walk_expr(self, expr),
337337
}
338338
}
339+
340+
fn visit_stmt(&mut self, stmt: &mut Stmt) {
341+
// This function is not called by visit_block above, so the only time it will be used is for
342+
// top-level statement fragments. Given that, the qubits allocated will always be live for
343+
// the entirety of a global scope, so only qubit allocations need to be generated.
344+
match take(&mut stmt.kind) {
345+
StmtKind::Qubit(_, pat, qubit_init, None) => {
346+
stmt.kind = create_qubit_global_alloc(self.core, pat, qubit_init);
347+
}
348+
StmtKind::Qubit(_, pat, qubit_init, block) => {
349+
let stmts = self.process_qubit_stmt(stmt.span, pat, qubit_init, block);
350+
*stmt = stmts[0].clone();
351+
}
352+
kind => {
353+
stmt.kind = kind;
354+
walk_stmt(self, stmt);
355+
}
356+
}
357+
}
358+
}
359+
360+
fn create_qubit_global_alloc(core: &Table, pat: Pat, qubit_init: QubitInit) -> StmtKind {
361+
fn qubit_alloc_expr(core: &Table, qubit_init: QubitInit) -> Expr {
362+
match qubit_init.kind {
363+
QubitInitKind::Array(mut expr) => creat_qubit_alloc_call_expr(
364+
qubit_init.span,
365+
create_gen_core_ref(core, "QIR.Runtime", "AllocateQubitArray", qubit_init.span),
366+
Some(take(&mut expr)),
367+
),
368+
QubitInitKind::Single => creat_qubit_alloc_call_expr(
369+
qubit_init.span,
370+
create_gen_core_ref(
371+
core,
372+
"QIR.Runtime",
373+
"__quantum__rt__qubit_allocate",
374+
qubit_init.span,
375+
),
376+
None,
377+
),
378+
QubitInitKind::Tuple(tup) => Expr {
379+
id: NodeId::default(),
380+
span: qubit_init.span,
381+
ty: qubit_init.ty,
382+
kind: ExprKind::Tuple(
383+
tup.into_iter()
384+
.map(|init| qubit_alloc_expr(core, init))
385+
.collect(),
386+
),
387+
},
388+
}
389+
}
390+
391+
StmtKind::Local(
392+
Mutability::Immutable,
393+
pat,
394+
qubit_alloc_expr(core, qubit_init),
395+
)
339396
}
340397

341398
fn create_general_alloc_stmt(
@@ -345,23 +402,27 @@ fn create_general_alloc_stmt(
345402
) -> Stmt {
346403
ident.gen_id_init(
347404
Mutability::Immutable,
348-
Expr {
349-
id: NodeId::default(),
350-
span: ident.span,
351-
ty: Ty::Prim(PrimTy::Qubit),
352-
kind: ExprKind::Call(
353-
Box::new(call_expr),
354-
Box::new(array_size.unwrap_or(Expr {
355-
id: NodeId::default(),
356-
span: ident.span,
357-
ty: Ty::UNIT,
358-
kind: ExprKind::Tuple(vec![]),
359-
})),
360-
),
361-
},
405+
creat_qubit_alloc_call_expr(ident.span, call_expr, array_size),
362406
)
363407
}
364408

409+
fn creat_qubit_alloc_call_expr(span: Span, call_expr: Expr, array_size: Option<Expr>) -> Expr {
410+
Expr {
411+
id: NodeId::default(),
412+
span,
413+
ty: Ty::Prim(PrimTy::Qubit),
414+
kind: ExprKind::Call(
415+
Box::new(call_expr),
416+
Box::new(array_size.unwrap_or(Expr {
417+
id: NodeId::default(),
418+
span,
419+
ty: Ty::UNIT,
420+
kind: ExprKind::Tuple(vec![]),
421+
})),
422+
),
423+
}
424+
}
425+
365426
fn create_general_dealloc_stmt(call_expr: Expr, ident: &IdentTemplate) -> Stmt {
366427
Stmt {
367428
id: NodeId::default(),

0 commit comments

Comments
 (0)