Skip to content

Commit

Permalink
Add support to while loops in OpenQASM3 frontend (#5)
Browse files Browse the repository at this point in the history
This PR adds support to while loop in OpenQASM3 frontend. 

For a OpenQASM3 program:
```qasm
OPENQASM 3.0;

gate h q {
    U(1.57079632679, 0.0, 3.14159265359) q;
}

qubit $0;
int n = 5;

while (n > 0) {
    h $0;
    // error: Binary operation ASTOpTypeSub not supported yet.
    // n = n - 1;
}
```

generates MLIR:
```mlir
...
scf.while : () -> () {
    %2 = quir.use_variable @n : i32
    %c0_i32_0 = arith.constant 0 : i32
    %3 = arith.cmpi sgt, %2, %c0_i32_0 : i32
    scf.condition(%3)
} do {
    quir.call_gate @h(%0) : (!quir.qubit<1>) -> ()
    %cst = constant unit
    scf.yield
    }
}
...
```
  • Loading branch information
SooluThomas committed Dec 15, 2022
1 parent e7c9e09 commit 3019de5
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 22 deletions.
26 changes: 21 additions & 5 deletions lib/Frontend/OpenQASM3/QUIRGenQASM3Visitor.cpp
Expand Up @@ -361,7 +361,7 @@ void QUIRGenQASM3Visitor::visit(const ASTIfStatementNode *node) {
}

void QUIRGenQASM3Visitor::visit(const ASTElseStatementNode *node) {
// This is processed with the IfStatementNode.
// This is processed with the ASTIfStatementNode.
}

void QUIRGenQASM3Visitor::visit(const ASTSwitchStatementNode *node) {
Expand Down Expand Up @@ -443,13 +443,29 @@ void QUIRGenQASM3Visitor::visit(const ASTSwitchStatementNode *node) {
}

void QUIRGenQASM3Visitor::visit(const ASTWhileStatementNode *node) {
reportError(node, mlir::DiagnosticSeverity::Error)
<< "While loops are not yet supported.";
const ASTWhileLoopNode *loop = node->GetLoop();
Location loc = getLocation(node);

auto whileOp =
builder.create<scf::WhileOp>(loc, TypeRange({}), ValueRange({}));
builder.createBlock(&whileOp.getBefore());

const ASTExpressionNode *exprNode = loop->GetExpression();
Value condition = visitAndGetExpressionValue(exprNode);

builder.create<scf::ConditionOp>(loc, condition, ValueRange({}));

builder.createBlock(&whileOp.getAfter());

const ASTStatementList &statementList = loop->GetStatementList();
BaseQASM3Visitor::visit(&statementList);

builder.create<scf::YieldOp>(loc);
builder.setInsertionPointAfter(whileOp);
}

void QUIRGenQASM3Visitor::visit(const ASTWhileLoopNode *node) {
reportError(node, mlir::DiagnosticSeverity::Error)
<< "While loops are not yet supported.";
// This is processed with the ASTWhileStatementNode.
}

void QUIRGenQASM3Visitor::visit(const ASTReturnStatementNode *node) {
Expand Down
46 changes: 46 additions & 0 deletions test/Frontend/OpenQASM3/while-1.qasm
@@ -0,0 +1,46 @@
OPENQASM 3.0;
// RUN: qss-compiler -X=qasm --emit=ast-pretty %s | FileCheck %s --match-full-lines --check-prefix AST-PRETTY
// RUN: qss-compiler -X=qasm --emit=mlir %s | FileCheck %s --match-full-lines --check-prefix MLIR

gate h q {
U(1.57079632679, 0.0, 3.14159265359) q;
}

qubit $0;
int n = 1;

bit is_excited;

// AST-PRETTY: WhileStatement(condition=BinaryOpNode(type=ASTOpTypeCompNeq, left=IdentifierNode(name=n, bits=32), right=IntNode(signed=true, value=0, bits=32))
// MLIR: scf.while : () -> () {
// MLIR: %2 = quir.use_variable @n : i32
// MLIR: %c0_i32_0 = arith.constant 0 : i32
// MLIR: %3 = arith.cmpi ne, %2, %c0_i32_0 : i32
// MLIR: scf.condition(%3)
// MLIR: } do {
while (n != 0) {
// AST-PRETTY: statements=
// AST-PRETTY: HGateOpNode(params=[], qubits=[], qcparams=[$0])
// MLIR: quir.call_gate @h(%0) : (!quir.qubit<1>) -> ()
// MLIR: %cst = constant unit
h $0;
// MLIR: %2 = quir.measure(%0) : (!quir.qubit<1>) -> i1
// MLIR: quir.assign_cbit_bit @is_excited<1> [0] : i1 = %2
// MLIR: %3 = quir.use_variable @is_excited : !quir.cbit<1>
// MLIR: %4 = "quir.cast"(%3) : (!quir.cbit<1>) -> i1
is_excited = measure $0;
// MLIR: scf.if %4 {
if (is_excited) {
// MLIR: quir.call_gate @h(%0) : (!quir.qubit<1>) -> ()
// MLIR: %cst_1 = constant unit
// MLIR: }
h $0;
}
// error: Binary operation ASTOpTypeSub not supported yet.
// n = n - 1;
// MLIR: %c0_i32_0 = arith.constant 0 : i32
// MLIR: quir.assign_variable @n : i32 = %c0_i32_0
n = 0; // workaround for n = n - 1
// MLIR: scf.yield
}
// AST-PRETTY: )
46 changes: 46 additions & 0 deletions test/Frontend/OpenQASM3/while-2.qasm
@@ -0,0 +1,46 @@
OPENQASM 3.0;
// RUN: qss-compiler -X=qasm --emit=ast-pretty %s | FileCheck %s --match-full-lines --check-prefix AST-PRETTY
// RUN: qss-compiler -X=qasm --emit=mlir %s | FileCheck %s --match-full-lines --check-prefix MLIR

gate h q {
U(1.57079632679, 0.0, 3.14159265359) q;
}

qubit $0;
int n = 2;
bit is_excited;

// AST-PRETTY: WhileStatement(condition=BinaryOpNode(type=ASTOpTypeCompNeq, left=IdentifierNode(name=n, bits=32), right=IntNode(signed=true, value=0, bits=32))
// MLIR: scf.while : () -> () {
// MLIR: %2 = quir.use_variable @n : i32
// MLIR: %c0_i32_0 = arith.constant 0 : i32
// MLIR: %3 = arith.cmpi ne, %2, %c0_i32_0 : i32
// MLIR: scf.condition(%3)
// MLIR: } do {
while (n != 0) {
// MLIR: %2 = quir.use_variable @n : i32
// MLIR: %c2_i32_0 = arith.constant 2 : i32
// MLIR: %3 = arith.cmpi eq, %2, %c2_i32_0 : i32
// MLIR: scf.if %3 {
if (n == 2) {
// MLIR: quir.call_gate @h(%0) : (!quir.qubit<1>) -> ()
// MLIR: %cst = constant unit
// MLIR: %c1_i32 = arith.constant 1 : i32
// MLIR: quir.assign_variable @n : i32 = %c1_i32
h $0;
n = 1;
// MLIR: } else {
} else {
// MLIR: quir.call_gate @h(%0) : (!quir.qubit<1>) -> ()
// MLIR: %cst = constant unit
// MLIR: %4 = quir.measure(%0) : (!quir.qubit<1>) -> i1
// MLIR: quir.assign_cbit_bit @is_excited<1> [0] : i1 = %4
// MLIR: %c0_i32_1 = arith.constant 0 : i32
// MLIR: quir.assign_variable @n : i32 = %c0_i32_1
h $0;
is_excited = measure $0;
n = 0;
}
// MLIR: scf.yield
}
// AST-PRETTY: )
17 changes: 0 additions & 17 deletions test/Frontend/OpenQASM3/while.qasm

This file was deleted.

0 comments on commit 3019de5

Please sign in to comment.