Skip to content

Commit

Permalink
Optimize RIR reindexing, QIR qubit use (#1938)
Browse files Browse the repository at this point in the history
This change updates the behavior of the RIR qubit reindexing to assume
single block only and then take additional steps to optimize qubit usage
with that block. This is consistent with the assumption that qubit reuse
is required for adaptive programs rather than a separately configurable
capability.

In addition, updates the qasm3 compiling to take advantage of this
optimization by having explicitly call `__quantum__qis__m__body`, and
updates the corresponding tests.
  • Loading branch information
swernli authored Sep 26, 2024
1 parent 1a725b1 commit 6c3ab39
Show file tree
Hide file tree
Showing 10 changed files with 203 additions and 629 deletions.
48 changes: 47 additions & 1 deletion compiler/qsc_qasm3/src/ast_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -652,8 +652,16 @@ pub(crate) fn build_measure_call(
expr: ast::Expr,
name_span: Span,
operand_span: Span,
stmt_span: Span,
) -> ast::Expr {
build_global_call_with_one_param("M", expr, name_span, operand_span)
build_call_with_param(
"__quantum__qis__m__body",
&["QIR", "Intrinsic"],
expr,
name_span,
operand_span,
stmt_span,
)
}

pub(crate) fn build_reset_call(expr: ast::Expr, name_span: Span, operand_span: Span) -> ast::Expr {
Expand Down Expand Up @@ -792,6 +800,44 @@ pub(crate) fn build_call_no_params(name: &str, idents: &[&str], span: Span) -> E
}
}

pub(crate) fn build_call_with_param(
name: &str,
idents: &[&str],
operand: Expr,
name_span: Span,
operand_span: Span,
stmt_span: Span,
) -> Expr {
let segments = build_idents(idents);
let fn_name = Ident {
name: Rc::from(name),
span: name_span,
..Default::default()
};
let path_expr = Expr {
kind: Box::new(ExprKind::Path(Box::new(Path {
segments,
name: Box::new(fn_name),
..Default::default()
}))),
..Default::default()
};
let call = ExprKind::Call(
Box::new(path_expr),
Box::new(Expr {
kind: Box::new(ExprKind::Paren(Box::new(operand))),
span: operand_span,
..Default::default()
}),
);

Expr {
id: NodeId::default(),
span: stmt_span,
kind: Box::new(call),
}
}

pub(crate) fn build_lit_double_expr(value: f64, span: Span) -> Expr {
Expr {
id: NodeId::default(),
Expand Down
3 changes: 2 additions & 1 deletion compiler/qsc_qasm3/src/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2002,6 +2002,7 @@ impl QasmCompiler {
return None;
};
let name_span = span_for_syntax_token(&measure_token);
let stmt_span = span_for_syntax_node(measure_expr.syntax());

let Some(operand) = measure_expr.gate_operand() else {
let span = span_for_syntax_node(expr.syntax());
Expand All @@ -2012,7 +2013,7 @@ impl QasmCompiler {

let args = self.compile_gate_operand(&operand)?;
let operand_span = span_for_syntax_node(operand.syntax());
let expr = build_measure_call(args.expr, name_span, operand_span);
let expr = build_measure_call(args.expr, name_span, operand_span, stmt_span);

Some(QasmTypedExpr {
ty: Type::Bit(IsConst::False),
Expand Down
104 changes: 47 additions & 57 deletions compiler/qsc_qasm3/src/tests/output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,7 @@ fn using_re_semantics_removes_output() -> miette::Result<(), Vec<Report>> {
);
fail_on_compilation_errors(&unit);
let qsharp = gen_qsharp(&unit.package.expect("no package found"));
expect![
r#"
expect![[r#"
namespace qasm3_import {
operation Test(theta : Double, beta : Int) : Unit {
mutable c = [Zero, Zero];
Expand All @@ -58,11 +57,10 @@ fn using_re_semantics_removes_output() -> miette::Result<(), Vec<Report>> {
Rz(theta, q[0]);
H(q[0]);
CNOT(q[0], q[1]);
set c w/= 0 <- M(q[0]);
set c w/= 1 <- M(q[1]);
set c w/= 0 <- QIR.Intrinsic.__quantum__qis__m__body(q[0]);
set c w/= 1 <- QIR.Intrinsic.__quantum__qis__m__body(q[1]);
}
}"#
]
}"#]]
.assert_eq(&qsharp);

Ok(())
Expand Down Expand Up @@ -102,8 +100,7 @@ fn using_qasm_semantics_captures_all_classical_decls_as_output() -> miette::Resu
);
fail_on_compilation_errors(&unit);
let qsharp = gen_qsharp(&unit.package.expect("no package found"));
expect![
r#"
expect![[r#"
namespace qasm3_import {
operation Test(theta : Double, beta : Int) : (Result[], Double, Double) {
mutable c = [Zero, Zero];
Expand All @@ -113,12 +110,11 @@ fn using_qasm_semantics_captures_all_classical_decls_as_output() -> miette::Resu
Rz(theta, q[0]);
H(q[0]);
CNOT(q[0], q[1]);
set c w/= 0 <- M(q[0]);
set c w/= 1 <- M(q[1]);
set c w/= 0 <- QIR.Intrinsic.__quantum__qis__m__body(q[0]);
set c w/= 1 <- QIR.Intrinsic.__quantum__qis__m__body(q[1]);
(c, gamma, delta)
}
}"#
]
}"#]]
.assert_eq(&qsharp);

Ok(())
Expand Down Expand Up @@ -158,23 +154,21 @@ fn using_qiskit_semantics_only_bit_array_is_captured_and_reversed(
);
fail_on_compilation_errors(&unit);
let qsharp = gen_qsharp(&unit.package.expect("no package found"));
expect![
r#"
namespace qasm3_import {
operation Test(theta : Double, beta : Int) : Result[] {
mutable c = [Zero, Zero];
let q = QIR.Runtime.AllocateQubitArray(2);
mutable gamma = 0.;
mutable delta = 0.;
Rz(theta, q[0]);
H(q[0]);
CNOT(q[0], q[1]);
set c w/= 0 <- M(q[0]);
set c w/= 1 <- M(q[1]);
Microsoft.Quantum.Arrays.Reversed(c)
}
}"#
]
expect![[r#"
namespace qasm3_import {
operation Test(theta : Double, beta : Int) : Result[] {
mutable c = [Zero, Zero];
let q = QIR.Runtime.AllocateQubitArray(2);
mutable gamma = 0.;
mutable delta = 0.;
Rz(theta, q[0]);
H(q[0]);
CNOT(q[0], q[1]);
set c w/= 0 <- QIR.Intrinsic.__quantum__qis__m__body(q[0]);
set c w/= 1 <- QIR.Intrinsic.__quantum__qis__m__body(q[1]);
Microsoft.Quantum.Arrays.Reversed(c)
}
}"#]]
.assert_eq(&qsharp);

Ok(())
Expand Down Expand Up @@ -222,30 +216,28 @@ c2[2] = measure q[4];
fail_on_compilation_errors(&unit);
let package = unit.package.expect("no package found");
let qsharp = gen_qsharp(&package.clone());
expect![
r#"
namespace qasm3_import {
operation Test(theta : Double, beta : Int) : (Result[], Result[]) {
mutable c = [Zero, Zero];
mutable c2 = [Zero, Zero, Zero];
let q = QIR.Runtime.AllocateQubitArray(5);
mutable gamma = 0.;
mutable delta = 0.;
Rz(theta, q[0]);
H(q[0]);
CNOT(q[0], q[1]);
X(q[2]);
I(q[3]);
X(q[4]);
set c w/= 0 <- M(q[0]);
set c w/= 1 <- M(q[1]);
set c2 w/= 0 <- M(q[2]);
set c2 w/= 1 <- M(q[3]);
set c2 w/= 2 <- M(q[4]);
(Microsoft.Quantum.Arrays.Reversed(c2), Microsoft.Quantum.Arrays.Reversed(c))
}
}"#
]
expect![[r#"
namespace qasm3_import {
operation Test(theta : Double, beta : Int) : (Result[], Result[]) {
mutable c = [Zero, Zero];
mutable c2 = [Zero, Zero, Zero];
let q = QIR.Runtime.AllocateQubitArray(5);
mutable gamma = 0.;
mutable delta = 0.;
Rz(theta, q[0]);
H(q[0]);
CNOT(q[0], q[1]);
X(q[2]);
I(q[3]);
X(q[4]);
set c w/= 0 <- QIR.Intrinsic.__quantum__qis__m__body(q[0]);
set c w/= 1 <- QIR.Intrinsic.__quantum__qis__m__body(q[1]);
set c2 w/= 0 <- QIR.Intrinsic.__quantum__qis__m__body(q[2]);
set c2 w/= 1 <- QIR.Intrinsic.__quantum__qis__m__body(q[3]);
set c2 w/= 2 <- QIR.Intrinsic.__quantum__qis__m__body(q[4]);
(Microsoft.Quantum.Arrays.Reversed(c2), Microsoft.Quantum.Arrays.Reversed(c))
}
}"#]]
.assert_eq(&qsharp);

Ok(())
Expand Down Expand Up @@ -279,8 +271,7 @@ c2[2] = measure q[4];
"#;

let qir = compile_qasm_to_qir(source, Profile::AdaptiveRI)?;
expect![
r#"
expect![[r#"
%Result = type opaque
%Qubit = type opaque
Expand Down Expand Up @@ -344,8 +335,7 @@ attributes #1 = { "irreversible" }
!8 = !{i32 1, !"classical_fixed_points", i1 false}
!9 = !{i32 1, !"user_functions", i1 false}
!10 = !{i32 1, !"multiple_target_branching", i1 false}
"#
]
"#]]
.assert_eq(&qir);

Ok(())
Expand Down
34 changes: 12 additions & 22 deletions compiler/qsc_qasm3/src/tests/statement/if_stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,17 @@ fn can_use_cond_with_implicit_cast_to_bool() -> miette::Result<(), Vec<Report>>
"#;

let qsharp = compile_qasm_to_qsharp(source)?;
expect![
r#"
expect![[r#"
function __ResultAsBool__(input : Result) : Bool {
Microsoft.Quantum.Convert.ResultAsBool(input)
}
let q = QIR.Runtime.__quantum__rt__qubit_allocate();
H(q);
mutable result = M(q);
mutable result = QIR.Intrinsic.__quantum__qis__m__body(q);
if __ResultAsBool__(result) {
Reset(q);
};
"#
]
"#]]
.assert_eq(&qsharp);
Ok(())
}
Expand All @@ -52,19 +50,17 @@ fn can_use_negated_cond_with_implicit_cast_to_bool() -> miette::Result<(), Vec<R
"#;

let qsharp = compile_qasm_to_qsharp(source)?;
expect![
r#"
expect![[r#"
function __ResultAsBool__(input : Result) : Bool {
Microsoft.Quantum.Convert.ResultAsBool(input)
}
let q = QIR.Runtime.__quantum__rt__qubit_allocate();
H(q);
mutable result = M(q);
mutable result = QIR.Intrinsic.__quantum__qis__m__body(q);
if not __ResultAsBool__(result) {
Reset(q);
};
"#
]
"#]]
.assert_eq(&qsharp);
Ok(())
}
Expand All @@ -84,14 +80,12 @@ fn then_branch_can_be_stmt() -> miette::Result<(), Vec<Report>> {
"#;

let qsharp = compile_qasm_to_qsharp(source)?;
expect![
r#"
expect![[r#"
let q = QIR.Runtime.__quantum__rt__qubit_allocate();
if 0 == 1 {
Z(q);
};
"#
]
"#]]
.assert_eq(&qsharp);
Ok(())
}
Expand All @@ -107,16 +101,14 @@ fn else_branch_can_be_stmt() -> miette::Result<(), Vec<Report>> {
"#;

let qsharp = compile_qasm_to_qsharp(source)?;
expect![
r#"
expect![[r#"
let q = QIR.Runtime.__quantum__rt__qubit_allocate();
if 0 == 1 {
Z(q);
} else {
Y(q);
};
"#
]
"#]]
.assert_eq(&qsharp);
Ok(())
}
Expand All @@ -132,16 +124,14 @@ fn then_and_else_branch_can_be_stmt() -> miette::Result<(), Vec<Report>> {
"#;

let qsharp = compile_qasm_to_qsharp(source)?;
expect![
r#"
expect![[r#"
let q = QIR.Runtime.__quantum__rt__qubit_allocate();
if 0 == 1 {
Z(q);
} else {
Y(q);
};
"#
]
"#]]
.assert_eq(&qsharp);
Ok(())
}
Expand Down
8 changes: 3 additions & 5 deletions compiler/qsc_qasm3/src/tests/statement/include.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,7 @@ fn programs_with_includes_can_be_parsed() -> miette::Result<(), Vec<Report>> {
),
);
let qsharp = qsharp_from_qasm_compilation(r)?;
expect![
r#"
expect![[r#"
namespace qasm3_import {
@EntryPoint()
operation Test() : Result[] {
Expand All @@ -58,11 +57,10 @@ fn programs_with_includes_can_be_parsed() -> miette::Result<(), Vec<Report>> {
mutable c = [Zero];
let q = QIR.Runtime.AllocateQubitArray(1);
my_gate(q[0]);
set c w/= 0 <- M(q[0]);
set c w/= 0 <- QIR.Intrinsic.__quantum__qis__m__body(q[0]);
Microsoft.Quantum.Arrays.Reversed(c)
}
}"#
]
}"#]]
.assert_eq(&qsharp);
Ok(())
}
Loading

0 comments on commit 6c3ab39

Please sign in to comment.