Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 20 additions & 77 deletions compiler/qsc_qasm/src/semantic/lowerer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ use crate::convert::safe_i64_to_f64;
use crate::parser::ast::list_from_iter;
use crate::parser::ast::List;
use crate::parser::QasmSource;
use crate::semantic::ast::Expr;
use crate::semantic::types::base_types_equal;
use crate::semantic::types::can_cast_literal;
use crate::semantic::types::can_cast_literal_with_value_knowledge;
Expand Down Expand Up @@ -278,10 +277,7 @@ impl Lowerer {
}]
}

/// Define the standard gates in the symbol table.
/// The sdg, tdg, crx, cry, crz, and ch are defined
/// as their bare gates, and modifiers are applied
/// when calling them.
/// Define the `OpenQASM` 3.0 standard gates in the symbol table.
fn define_stdgates(&mut self, span: Span) {
fn gate_symbol(name: &str, cargs: u32, qargs: u32) -> Symbol {
Symbol::new(
Expand All @@ -298,21 +294,29 @@ impl Lowerer {
gate_symbol("y", 0, 1),
gate_symbol("z", 0, 1),
gate_symbol("h", 0, 1),
gate_symbol("ch", 0, 2),
gate_symbol("s", 0, 1),
gate_symbol("sdg", 0, 1),
gate_symbol("t", 0, 1),
gate_symbol("tdg", 0, 1),
gate_symbol("sx", 0, 1),
gate_symbol("rx", 1, 1),
gate_symbol("ry", 1, 1),
gate_symbol("rz", 1, 1),
gate_symbol("crx", 1, 2),
gate_symbol("cry", 1, 2),
gate_symbol("crz", 1, 2),
gate_symbol("cx", 0, 2),
gate_symbol("cy", 0, 2),
gate_symbol("cz", 0, 2),
gate_symbol("cp", 1, 2),
gate_symbol("swap", 0, 2),
gate_symbol("cswap", 0, 3),
gate_symbol("ccx", 0, 3),
gate_symbol("cu", 4, 2),
gate_symbol("CX", 0, 2),
gate_symbol("phase", 1, 1),
gate_symbol("cphase", 1, 2),
gate_symbol("id", 0, 1),
gate_symbol("u1", 1, 1),
gate_symbol("u2", 2, 1),
Expand All @@ -326,10 +330,7 @@ impl Lowerer {
}
}

/// Define the standard gates in the symbol table.
/// The sdg, tdg, crx, cry, crz, and ch are defined
/// as their bare gates, and modifiers are applied
/// when calling them.
/// Define the `OpenQASM` 2.0 standard gates in the symbol table.
fn define_qelib1_gates(&mut self, span: Span) {
fn gate_symbol(name: &str, cargs: u32, qargs: u32) -> Symbol {
Symbol::new(
Expand All @@ -346,30 +347,29 @@ impl Lowerer {
gate_symbol("u3", 3, 1),
gate_symbol("u2", 2, 1),
gate_symbol("u1", 1, 1),
//gate_symbol("cx", 0, 2), // handled as a modified x
gate_symbol("cx", 0, 2),
gate_symbol("id", 0, 1),
// --- QE Standard Gates ---
gate_symbol("x", 0, 1),
gate_symbol("y", 0, 1),
gate_symbol("z", 0, 1),
gate_symbol("h", 0, 1),
gate_symbol("s", 0, 1),
// sdg handled as a modified s
gate_symbol("sdg", 0, 1),
gate_symbol("t", 0, 1),
// tdg handled as a modified t

gate_symbol("tdg", 0, 1),
// --- Standard rotations ---
gate_symbol("rx", 1, 1),
gate_symbol("ry", 1, 1),
gate_symbol("rz", 1, 1),
// --- QE Standard User-Defined Gates ---
//gate_symbol("cz", 0, 2), // handled as a modified z
//gate_symbol("cy", 0, 2), // handled as a modified y
// ch handled as a modified h
gate_symbol("cz", 0, 2),
gate_symbol("cy", 0, 2),
gate_symbol("ch", 0, 2),
gate_symbol("ccx", 0, 3),
// crz handled as a modified rz
// cu1 handled as a modified u1
// cu3 handled as a modified u3
gate_symbol("crz", 1, 2),
gate_symbol("cu1", 1, 2),
gate_symbol("cu3", 3, 2),
];
for gate in gates {
let name = gate.name.clone();
Expand Down Expand Up @@ -1892,18 +1892,7 @@ impl Lowerer {
self.push_unsupported_error_message("gate call duration", duration.span);
}

let mut name = stmt.name.name.to_string();
if let Some((gate_name, implicit_modifier)) =
self.try_get_qsharp_name_and_implicit_modifiers(&name, stmt.name.span)
{
// Override the gate name if we mapped with modifiers.
name = gate_name;

// 2. Get implicit modifiers and make them explicit.
// Q: Do we need this during lowering?
// A: Yes, we need it to check the gate_call arity.
modifiers.push(implicit_modifier);
}
let name = stmt.name.name.to_string();

// need a workaround for qiskit generating gate calls without having declared the gate
self.define_qiskit_standard_gate_if_needed(&name, stmt.name.span);
Expand Down Expand Up @@ -4129,52 +4118,6 @@ impl Lowerer {
let error = crate::Error(kind);
WithSource::from_map(&self.source_map, error)
}

fn try_get_qsharp_name_and_implicit_modifiers<S: AsRef<str>>(
&self,
gate_name: S,
name_span: Span,
) -> Option<(String, semantic::QuantumGateModifier)> {
use semantic::GateModifierKind::*;

let make_modifier = |kind| semantic::QuantumGateModifier {
span: name_span,
modifier_keyword_span: name_span,
kind,
};
let ctrl_expr = Expr::uint(1, Span::default());

if self.version == Some(QASM2_VERSION) {
match gate_name.as_ref() {
"cx" => Some(("x".to_string(), make_modifier(Ctrl(ctrl_expr)))),
"sdg" => Some(("s".to_string(), make_modifier(Inv))),
"tdg" => Some(("t".to_string(), make_modifier(Inv))),
"cz" => Some(("z".to_string(), make_modifier(Ctrl(ctrl_expr)))),
"cy" => Some(("y".to_string(), make_modifier(Ctrl(ctrl_expr)))),
"ch" => Some(("h".to_string(), make_modifier(Ctrl(ctrl_expr)))),
"crz" => Some(("rz".to_string(), make_modifier(Ctrl(ctrl_expr)))),
"cu1" => Some(("u1".to_string(), make_modifier(Ctrl(ctrl_expr)))),
"cu3" => Some(("u3".to_string(), make_modifier(Ctrl(ctrl_expr)))),
_ => None,
}
} else {
match gate_name.as_ref() {
"cy" => Some(("y".to_string(), make_modifier(Ctrl(ctrl_expr)))),
"cz" => Some(("z".to_string(), make_modifier(Ctrl(ctrl_expr)))),
"ch" => Some(("h".to_string(), make_modifier(Ctrl(ctrl_expr)))),
"crx" => Some(("rx".to_string(), make_modifier(Ctrl(ctrl_expr)))),
"cry" => Some(("ry".to_string(), make_modifier(Ctrl(ctrl_expr)))),
"crz" => Some(("rz".to_string(), make_modifier(Ctrl(ctrl_expr)))),
"cswap" => Some(("swap".to_string(), make_modifier(Ctrl(ctrl_expr)))),
"sdg" => Some(("s".to_string(), make_modifier(Inv))),
"tdg" => Some(("t".to_string(), make_modifier(Inv))),
// Gates for OpenQASM 2 backwards compatibility
"CX" => Some(("x".to_string(), make_modifier(Ctrl(ctrl_expr)))),
"cphase" => Some(("phase".to_string(), make_modifier(Ctrl(ctrl_expr)))),
_ => None,
}
}
}
}

fn wrap_expr_in_cast_expr(ty: Type, rhs: semantic::Expr) -> semantic::Expr {
Expand Down
18 changes: 9 additions & 9 deletions compiler/qsc_qasm/src/semantic/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,50 +191,50 @@ fn semantic_errors_map_to_their_corresponding_file_specific_spans() {
Stmt [196-206]:
annotations: <empty>
kind: ClassicalDeclarationStmt [196-206]:
symbol_id: 32
symbol_id: 40
ty_span: [196-199]
init_expr: Expr [204-205]:
ty: const bit
kind: Lit: Bit(1)
Stmt [211-227]:
annotations: <empty>
kind: ClassicalDeclarationStmt [211-227]:
symbol_id: 32
symbol_id: 40
ty_span: [211-215]
init_expr: Expr [220-226]:
ty: bool
kind: BinaryOpExpr:
op: AndL
lhs: Expr [220-221]:
ty: unknown
kind: SymbolId(33)
kind: SymbolId(41)
rhs: Expr [225-226]:
ty: bool
kind: Cast [0-0]:
ty: bool
expr: Expr [225-226]:
ty: bit
kind: SymbolId(32)
kind: SymbolId(40)
Stmt [140-154]:
annotations: <empty>
kind: ClassicalDeclarationStmt [140-154]:
symbol_id: 34
symbol_id: 42
ty_span: [140-145]
init_expr: Expr [150-153]:
ty: const angle
kind: Lit: Angle(0.7168146928204138)
Stmt [159-179]:
annotations: <empty>
kind: ClassicalDeclarationStmt [159-179]:
symbol_id: 35
symbol_id: 43
ty_span: [159-164]
init_expr: Expr [169-178]:
ty: float
kind: BinaryOpExpr:
op: Add
lhs: Expr [169-170]:
ty: angle
kind: SymbolId(34)
kind: SymbolId(42)
rhs: Expr [173-178]:
ty: float
kind: Cast [0-0]:
Expand All @@ -245,11 +245,11 @@ fn semantic_errors_map_to_their_corresponding_file_specific_spans() {
Stmt [74-84]:
annotations: <empty>
kind: ClassicalDeclarationStmt [74-84]:
symbol_id: 37
symbol_id: 45
ty_span: [74-77]
init_expr: Expr [82-83]:
ty: unknown
kind: SymbolId(36)
kind: SymbolId(44)

[Qasm.Lowerer.UndefinedSymbol

Expand Down
4 changes: 2 additions & 2 deletions compiler/qsc_qasm/src/semantic/tests/lowerer_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,9 @@ fn check_lowerer_error_spans_are_correct() {

x inconsistent types in alias expression: Expr [842-859]:
| ty: array[int, 2]
| kind: SymbolId(37), Expr [863-880]:
| kind: SymbolId(45), Expr [863-880]:
| ty: array[angle, 2]
| kind: SymbolId(38)
| kind: SymbolId(46)
,-[Test.qasm:37:1]
36 | array[angle, 2] alias_component_2 = {1.0, 2.0};
37 | let alias = alias_component_1 ++ alias_component_2;
Expand Down
10 changes: 5 additions & 5 deletions compiler/qsc_qasm/src/tests/statement/gate_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1493,8 +1493,8 @@ fn qasm2_all_qiskit_stdgates_can_be_called_included() -> miette::Result<(), Vec<
csdg(q[0], q[1]);
sxdg(q[0]);
csx(q[0], q[1]);
Controlled u1([q[1]], (Std.OpenQASM.Angle.DoubleAsAngle(Std.Math.PI() / 2., 53), q[0]));
Controlled u3([q[1]], (Std.OpenQASM.Angle.DoubleAsAngle(Std.Math.PI() / 2., 53), Std.OpenQASM.Angle.DoubleAsAngle(Std.Math.PI() / 4., 53), Std.OpenQASM.Angle.DoubleAsAngle(Std.Math.PI() / 8., 53), q[0]));
cu1(Std.OpenQASM.Angle.DoubleAsAngle(Std.Math.PI() / 2., 53), q[1], q[0]);
cu3(Std.OpenQASM.Angle.DoubleAsAngle(Std.Math.PI() / 2., 53), Std.OpenQASM.Angle.DoubleAsAngle(Std.Math.PI() / 4., 53), Std.OpenQASM.Angle.DoubleAsAngle(Std.Math.PI() / 8., 53), q[1], q[0]);
rccx(q[0], q[1], q[2]);
c3sqrtx(q[0], q[1], q[2], q[3]);
c3x(q[0], q[1], q[2], q[3]);
Expand Down Expand Up @@ -1542,9 +1542,9 @@ fn qasm2_broadcast_two_qubit_gate() -> miette::Result<(), Vec<Report>> {
import Std.OpenQASM.Intrinsic.*;
let ctrls = QIR.Runtime.AllocateQubitArray(3);
let targets = QIR.Runtime.AllocateQubitArray(3);
Controlled x([ctrls[0]], targets[0]);
Controlled x([ctrls[1]], targets[1]);
Controlled x([ctrls[2]], targets[2]);
cx(ctrls[0], targets[0]);
cx(ctrls[1], targets[1]);
cx(ctrls[2], targets[2]);
"#]]
.assert_eq(&qsharp);
Ok(())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ fn cy_gate_can_be_called() -> miette::Result<(), Vec<Report>> {
import Std.OpenQASM.Intrinsic.*;
let ctl = QIR.Runtime.__quantum__rt__qubit_allocate();
let target = QIR.Runtime.__quantum__rt__qubit_allocate();
Controlled y([ctl], target);
cy(ctl, target);
"#]]
.assert_eq(&qsharp);
Ok(())
Expand All @@ -39,7 +39,7 @@ fn cz_gate_can_be_called() -> miette::Result<(), Vec<Report>> {
import Std.OpenQASM.Intrinsic.*;
let ctl = QIR.Runtime.__quantum__rt__qubit_allocate();
let target = QIR.Runtime.__quantum__rt__qubit_allocate();
Controlled z([ctl], target);
cz(ctl, target);
"#]]
.assert_eq(&qsharp);
Ok(())
Expand All @@ -59,7 +59,7 @@ fn ch_gate_can_be_called() -> miette::Result<(), Vec<Report>> {
import Std.OpenQASM.Intrinsic.*;
let ctl = QIR.Runtime.__quantum__rt__qubit_allocate();
let target = QIR.Runtime.__quantum__rt__qubit_allocate();
Controlled h([ctl], target);
ch(ctl, target);
"#]]
.assert_eq(&qsharp);
Ok(())
Expand All @@ -77,7 +77,7 @@ fn sdg_gate_can_be_called() -> miette::Result<(), Vec<Report>> {
expect![[r#"
import Std.OpenQASM.Intrinsic.*;
let q = QIR.Runtime.__quantum__rt__qubit_allocate();
Adjoint s(q);
sdg(q);
"#]]
.assert_eq(&qsharp);
Ok(())
Expand All @@ -95,7 +95,7 @@ fn tdg_gate_can_be_called() -> miette::Result<(), Vec<Report>> {
expect![[r#"
import Std.OpenQASM.Intrinsic.*;
let q = QIR.Runtime.__quantum__rt__qubit_allocate();
Adjoint t(q);
tdg(q);
"#]]
.assert_eq(&qsharp);
Ok(())
Expand All @@ -115,10 +115,10 @@ fn crx_gate_can_be_called() -> miette::Result<(), Vec<Report>> {
import Std.OpenQASM.Intrinsic.*;
let ctl = QIR.Runtime.__quantum__rt__qubit_allocate();
let target = QIR.Runtime.__quantum__rt__qubit_allocate();
Controlled rx([ctl], (new Std.OpenQASM.Angle.Angle {
crx(new Std.OpenQASM.Angle.Angle {
Value = 716770142402832,
Size = 53
}, target));
}, ctl, target);
"#]]
.assert_eq(&qsharp);
Ok(())
Expand All @@ -138,10 +138,10 @@ fn cry_gate_can_be_called() -> miette::Result<(), Vec<Report>> {
import Std.OpenQASM.Intrinsic.*;
let ctl = QIR.Runtime.__quantum__rt__qubit_allocate();
let target = QIR.Runtime.__quantum__rt__qubit_allocate();
Controlled ry([ctl], (new Std.OpenQASM.Angle.Angle {
cry(new Std.OpenQASM.Angle.Angle {
Value = 716770142402832,
Size = 53
}, target));
}, ctl, target);
"#]]
.assert_eq(&qsharp);
Ok(())
Expand All @@ -161,10 +161,10 @@ fn crz_gate_can_be_called() -> miette::Result<(), Vec<Report>> {
import Std.OpenQASM.Intrinsic.*;
let ctl = QIR.Runtime.__quantum__rt__qubit_allocate();
let target = QIR.Runtime.__quantum__rt__qubit_allocate();
Controlled rz([ctl], (new Std.OpenQASM.Angle.Angle {
crz(new Std.OpenQASM.Angle.Angle {
Value = 716770142402832,
Size = 53
}, target));
}, ctl, target);
"#]]
.assert_eq(&qsharp);
Ok(())
Expand All @@ -184,7 +184,7 @@ fn cswap_gate_can_be_called() -> miette::Result<(), Vec<Report>> {
import Std.OpenQASM.Intrinsic.*;
let ctl = QIR.Runtime.__quantum__rt__qubit_allocate();
let q = QIR.Runtime.AllocateQubitArray(2);
Controlled swap([ctl], (q[0], q[1]));
cswap(ctl, q[0], q[1]);
"#]]
.assert_eq(&qsharp);
Ok(())
Expand All @@ -204,7 +204,7 @@ fn legacy_cx_gate_can_be_called() -> miette::Result<(), Vec<Report>> {
import Std.OpenQASM.Intrinsic.*;
let ctl = QIR.Runtime.__quantum__rt__qubit_allocate();
let target = QIR.Runtime.__quantum__rt__qubit_allocate();
Controlled x([ctl], target);
CX(ctl, target);
"#]]
.assert_eq(&qsharp);
Ok(())
Expand All @@ -224,10 +224,10 @@ fn legacy_cphase_gate_can_be_called() -> miette::Result<(), Vec<Report>> {
import Std.OpenQASM.Intrinsic.*;
let ctl = QIR.Runtime.__quantum__rt__qubit_allocate();
let target = QIR.Runtime.__quantum__rt__qubit_allocate();
Controlled phase([ctl], (new Std.OpenQASM.Angle.Angle {
cphase(new Std.OpenQASM.Angle.Angle {
Value = 1433540284805665,
Size = 53
}, target));
}, ctl, target);
"#]]
.assert_eq(&qsharp);
Ok(())
Expand Down
Loading