Skip to content

Broadcasting and slicing updates #2326

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 12 commits into
base: main
Choose a base branch
from
151 changes: 34 additions & 117 deletions compiler/qsc_qasm/src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ use crate::{
parser::ast::{list_from_iter, List},
semantic::{
ast::{
BinaryOpExpr, Cast, DiscreteSet, Expr, GateOperand, GateOperandKind, IndexElement,
IndexExpr, IndexSet, IndexedIdent, LiteralKind, MeasureExpr, TimeUnit, UnaryOpExpr,
BinaryOpExpr, Cast, Expr, GateOperand, GateOperandKind, Index, IndexExpr, IndexedIdent,
LiteralKind, MeasureExpr, Set, TimeUnit, UnaryOpExpr,
},
symbols::{IOKind, Symbol, SymbolId, SymbolTable},
types::{promote_types, ArrayDimensions, Type},
types::{promote_types, Type},
},
CompilerConfig, OperationSignature, OutputSemantics, ProgramType, QasmCompileUnit,
QubitSemantics,
Expand Down Expand Up @@ -425,7 +425,6 @@ impl QasmCompiler {
semast::StmtKind::Alias(stmt) => self.compile_alias_decl_stmt(stmt),
semast::StmtKind::Assign(stmt) => self.compile_assign_stmt(stmt),
semast::StmtKind::IndexedAssign(stmt) => self.compile_indexed_assign_stmt(stmt),
semast::StmtKind::AssignOp(stmt) => self.compile_assign_op_stmt(stmt),
semast::StmtKind::Barrier(stmt) => Self::compile_barrier_stmt(stmt),
semast::StmtKind::Box(stmt) => self.compile_box_stmt(stmt),
semast::StmtKind::Block(stmt) => self.compile_block_stmt(stmt),
Expand Down Expand Up @@ -488,17 +487,18 @@ impl QasmCompiler {
&mut self,
stmt: &semast::IndexedAssignStmt,
) -> Option<qsast::Stmt> {
let symbol = self.symbols[stmt.symbol_id].clone();
let symbol = self.symbols[stmt.indexed_ident.symbol_id].clone();

let indices: Vec<_> = stmt
.indexed_ident
.indices
.iter()
.map(|elem| self.compile_index_element(elem))
.map(|elem| self.compile_index(elem))
.collect();

let rhs = self.compile_expr(&stmt.rhs);

if stmt.indices.len() != 1 {
if stmt.indexed_ident.indices.len() != 1 {
self.push_unimplemented_error_message(
"multi-dimensional array index expressions",
stmt.span,
Expand All @@ -509,7 +509,7 @@ impl QasmCompiler {
let index_expr = indices[0].clone();

let stmt = build_indexed_assignment_statement(
stmt.name_span,
stmt.indexed_ident.name_span,
symbol.name.clone(),
index_expr,
rhs,
Expand All @@ -519,78 +519,6 @@ impl QasmCompiler {
Some(stmt)
}

fn compile_assign_op_stmt(&mut self, stmt: &semast::AssignOpStmt) -> Option<qsast::Stmt> {
// If the lhs is of type Angle, we call compile_assign_stmt with the rhs = lhs + rhs.
// This will call compile_binary_expr which handles angle & complex correctly.
if matches!(&stmt.lhs.ty, Type::Angle(..) | Type::Complex(..)) {
if stmt.indices.is_empty() {
let rhs = semast::Expr {
span: stmt.span,
ty: stmt.lhs.ty.clone(),
kind: Box::new(semast::ExprKind::BinaryOp(semast::BinaryOpExpr {
op: stmt.op,
lhs: stmt.lhs.clone(),
rhs: stmt.rhs.clone(),
})),
};

let stmt = semast::AssignStmt {
span: stmt.span,
symbol_id: stmt.symbol_id,
lhs_span: stmt.lhs.span,
rhs,
};

return self.compile_assign_stmt(&stmt);
}

if stmt.indices.len() != 1 {
self.push_unimplemented_error_message(
"multi-dimensional array index expressions",
stmt.span,
);
return None;
}

let lhs = semast::Expr {
span: stmt.span,
ty: stmt.lhs.ty.clone(),
kind: Box::new(semast::ExprKind::IndexExpr(semast::IndexExpr {
span: stmt.lhs.span,
collection: stmt.lhs.clone(),
index: *stmt.indices[0].clone(),
})),
};

let rhs = semast::Expr {
span: stmt.span,
ty: stmt.lhs.ty.clone(),
kind: Box::new(semast::ExprKind::BinaryOp(semast::BinaryOpExpr {
op: stmt.op,
lhs,
rhs: stmt.rhs.clone(),
})),
};

let stmt = semast::IndexedAssignStmt {
span: stmt.span,
symbol_id: stmt.symbol_id,
name_span: stmt.lhs.span,
indices: stmt.indices.clone(),
rhs,
};

return self.compile_indexed_assign_stmt(&stmt);
}

let lhs = self.compile_expr(&stmt.lhs);
let rhs = self.compile_expr(&stmt.rhs);
let qsop = Self::map_bin_op(stmt.op);

let expr = build_binary_expr(true, qsop, lhs, rhs, stmt.span);
Some(build_stmt_semi_from_expr(expr))
}

fn compile_barrier_stmt(stmt: &semast::BarrierStmt) -> Option<qsast::Stmt> {
Some(build_barrier_call(stmt.span))
}
Expand Down Expand Up @@ -1159,7 +1087,7 @@ impl QasmCompiler {
..Default::default()
},
semast::ExprKind::Ident(symbol_id) => self.compile_ident_expr(*symbol_id, expr.span),
semast::ExprKind::IndexedIdentifier(indexed_ident) => {
semast::ExprKind::IndexedIdent(indexed_ident) => {
self.compile_indexed_ident_expr(indexed_ident)
}
semast::ExprKind::UnaryOp(unary_op_expr) => self.compile_unary_op_expr(unary_op_expr),
Expand Down Expand Up @@ -1207,7 +1135,7 @@ impl QasmCompiler {
let index: Vec<_> = indexed_ident
.indices
.iter()
.map(|elem| self.compile_index_element(elem))
.map(|elem| self.compile_index(elem))
.collect();

if index.len() != 1 {
Expand Down Expand Up @@ -1411,7 +1339,7 @@ impl QasmCompiler {
crate::semantic::types::Type::Int(_, _) | crate::semantic::types::Type::UInt(_, _) => {
Self::cast_int_expr_to_ty(expr, &cast.expr.ty, &cast.ty, cast.span)
}
crate::semantic::types::Type::BitArray(ArrayDimensions::One(size), _) => {
crate::semantic::types::Type::BitArray(size, _) => {
Self::cast_bit_array_expr_to_ty(expr, &cast.expr.ty, &cast.ty, size, cast.span)
}
_ => err_expr(cast.span),
Expand All @@ -1426,14 +1354,22 @@ impl QasmCompiler {
}

fn compile_index_expr(&mut self, index_expr: &IndexExpr) -> qsast::Expr {
let expr = self.compile_expr(&index_expr.collection);
let index = self.compile_index_element(&index_expr.index);
let mut expr = self.compile_expr(&index_expr.collection);

qsast::Expr {
id: qsast::NodeId::default(),
span: index_expr.span,
kind: Box::new(qsast::ExprKind::Index(Box::new(expr), Box::new(index))),
for index in &index_expr.indices {
let index = self.compile_index(index);
let span = Span {
lo: index_expr.span.lo,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This lo span doesn't feel correct

Copy link
Contributor Author

@orpuente-MS orpuente-MS Apr 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no right answer here since the source syntax is different from Q#'s syntax.

The idea is that this source code

a[1, 2, 3, 4]

will get compiled to

a[1][2][3][4]

The span in your comment is the span of the expression being indexed. For example, if we are currently building a[1][2][3], the expression being indexed is a[1][2]. But in the source code this corresponds to a[1, 2, and that's what I'm setting the span to, which doesn't feel as intuitive as in Q#, but it's a best effort solution. Let me know if you can think of something better.

hi: index.span.hi,
};
expr = qsast::Expr {
id: qsast::NodeId::default(),
span,
kind: Box::new(qsast::ExprKind::Index(Box::new(expr), Box::new(index))),
}
}

expr
}

fn compile_paren_expr(&mut self, paren: &Expr, span: Span) -> qsast::Expr {
Expand Down Expand Up @@ -1465,14 +1401,14 @@ impl QasmCompiler {
}
}

fn compile_index_element(&mut self, elem: &IndexElement) -> qsast::Expr {
fn compile_index(&mut self, elem: &Index) -> qsast::Expr {
match elem {
IndexElement::DiscreteSet(discrete_set) => self.compile_discrete_set(discrete_set),
IndexElement::IndexSet(index_set) => self.compile_index_set(index_set),
Index::Expr(expr) => self.compile_expr(expr),
Index::Range(range) => self.compile_range_expr(range),
}
}

fn compile_discrete_set(&mut self, set: &DiscreteSet) -> qsast::Expr {
fn compile_set(&mut self, set: &Set) -> qsast::Expr {
let expr_list: Vec<_> = set
.values
.iter()
Expand All @@ -1482,28 +1418,15 @@ impl QasmCompiler {
build_expr_array_expr(expr_list, set.span)
}

fn compile_index_set(&mut self, set: &IndexSet) -> qsast::Expr {
// This is a temporary limitation. We can only handle
// single index expressions for now.
if set.values.len() == 1 {
if let semast::IndexSetItem::Expr(expr) = &*set.values[0] {
return self.compile_expr(expr);
}
}

self.push_unsupported_error_message("index set expressions with multiple values", set.span);
err_expr(set.span)
}

fn compile_enumerable_set(&mut self, set: &semast::EnumerableSet) -> qsast::Expr {
match set {
semast::EnumerableSet::DiscreteSet(set) => self.compile_discrete_set(set),
semast::EnumerableSet::Set(set) => self.compile_set(set),
semast::EnumerableSet::Expr(expr) => self.compile_expr(expr),
semast::EnumerableSet::RangeDefinition(range) => self.compile_range_expr(range),
semast::EnumerableSet::Range(range) => self.compile_range_expr(range),
}
}

fn compile_range_expr(&mut self, range: &semast::RangeDefinition) -> qsast::Expr {
fn compile_range_expr(&mut self, range: &semast::Range) -> qsast::Expr {
let Some(start) = &range.start else {
self.push_unimplemented_error_message("omitted range start", range.span);
return err_expr(range.span);
Expand Down Expand Up @@ -1692,10 +1615,7 @@ impl QasmCompiler {
size: u32,
span: Span,
) -> qsast::Expr {
assert!(matches!(
expr_ty,
Type::BitArray(ArrayDimensions::One(_), _)
));
assert!(matches!(expr_ty, Type::BitArray(_, _)));

let name_span = expr.span;
let operand_span = span;
Expand Down Expand Up @@ -1862,10 +1782,7 @@ impl QasmCompiler {
let name_span = expr.span;
let operand_span = span;
match ty {
Type::BitArray(dims, _) => {
let ArrayDimensions::One(size) = dims else {
return err_expr(span);
};
Type::BitArray(size, _) => {
let size = i64::from(*size);

let size_expr = build_lit_int_expr(size, Span::default());
Expand Down
Loading
Loading