Loading mlir/dialect/include/Quantum/QuantumOps.td +1 −1 Original line number Diff line number Diff line Loading @@ -238,7 +238,7 @@ def ConditionalOp : QuantumOp<"ifElseOp", []> { let summary = "if-then-else operation conditioned on a quantum Measure"; // Must be conditioned on a Result type let arguments = (ins ResultType:$result_bit); let results = (outs Variadic<AnyType>:$results); let results = (outs); let regions = (region SizedRegion<1>:$thenRegion, AnyRegion:$elseRegion); } Loading mlir/parsers/qasm3/examples/measure_conditional.qasm 0 → 100644 +10 −0 Original line number Diff line number Diff line OPENQASM 3; include "qelib1.inc"; qubit q; bit c; h q; c = measure q; if (c) { x q; } mlir/parsers/qasm3/utils/symbol_table.cpp +24 −0 Original line number Diff line number Diff line Loading @@ -144,4 +144,28 @@ void ScopedSymbolTable::evaluate_const_global(const std::string variable_name, // add_symbol(variable_name, x, {"const"}); return; } void ScopedSymbolTable::add_measure_bit_assignment( const mlir::Value &bit_var, const mlir::Value &result_var) { assert(result_var.getType().isa<mlir::OpaqueType>()); bit_var_ptr_to_meas_result_var[bit_var.getAsOpaquePointer()] = result_var; } std::optional<mlir::Value> ScopedSymbolTable::try_lookup_meas_result(const mlir::Value &bit_var) { const auto iter = bit_var_ptr_to_meas_result_var.find(bit_var.getAsOpaquePointer()); if (iter != bit_var_ptr_to_meas_result_var.end()) { return iter->second; } return std::nullopt; } std::optional<mlir::Value> ScopedSymbolTable::try_lookup_meas_result(const std::string &bit_var_name) { if (!has_symbol(bit_var_name)) { return std::nullopt; } return try_lookup_meas_result(get_symbol(bit_var_name)); } } // namespace qcor No newline at end of file mlir/parsers/qasm3/utils/symbol_table.hpp +11 −1 Original line number Diff line number Diff line Loading @@ -138,6 +138,12 @@ class ScopedSymbolTable { // Map Opaque Ptr of value to key in SymbolTable std::map<void*, std::string> replacement_helper; // Map Opaque Ptr of bit value to the originating Result* (from measure) // Note: after Measure, we perform a casting from Result* -> bool. // This map tracks the Result* returns by the measure op // so that we can trace the originating Result*. std::unordered_map<void *, mlir::Value> bit_var_ptr_to_meas_result_var; public: template <typename T> T get_global_constant(const std::string variable_name) { Loading Loading @@ -425,6 +431,10 @@ class ScopedSymbolTable { return array_qubit_symbol_name(qreg_name, std::to_string(index)); } void add_measure_bit_assignment(const mlir::Value &bit_var, const mlir::Value &result_var); std::optional<mlir::Value> try_lookup_meas_result(const mlir::Value &bit_var); std::optional<mlir::Value> try_lookup_meas_result(const std::string &bit_var_name); ~ScopedSymbolTable() {} }; } // namespace qcor No newline at end of file mlir/parsers/qasm3/visitor_handlers/conditional_handler.cpp +67 −0 Original line number Diff line number Diff line Loading @@ -2,6 +2,61 @@ #include "expression_handler.hpp" #include "qasm3_visitor.hpp" namespace { // ATM, we don't try to convert everything to the // special Quantum If-Then-Else Op. // Rather, we aim for very narrow use-case that we're sure // that this can be done. // i.e., this serve mainly as a stop-gap before fully-FTQC runtimes become // available. // Capture binary comparison conditional. // Note: currently, only bit-level is modeled. // (Some backends, e.g., Honeywell, support a richer set of comparison ops). struct BitComparisonExpression { std::string var_name; bool comparison_value; BitComparisonExpression(const std::string &var, bool val) : var_name(var), comparison_value(val) {} }; // Test if this is a simple bit check conditional: // e.g., // if (b) or if (b==1), etc. std::optional<BitComparisonExpression> tryParseSimpleBooleanExpression( qasm3Parser::BooleanExpressionContext &boolean_expr) { // std::cout << "conditional expr: " << boolean_expr.getText() << "\n"; if (boolean_expr.comparsionExpression()) { auto &comp_expr = *(boolean_expr.comparsionExpression()); if (comp_expr.expression().size() == 1) { return BitComparisonExpression(comp_expr.expression(0)->getText(), true); } if (comp_expr.expression().size() == 2 && comp_expr.relationalOperator()) { if (comp_expr.relationalOperator()->getText() == "==") { if (comp_expr.expression(1)->getText() == "1") { return BitComparisonExpression(comp_expr.expression(0)->getText(), true); } else { return BitComparisonExpression(comp_expr.expression(0)->getText(), false); } } if (comp_expr.relationalOperator()->getText() == "!=") { if (comp_expr.expression(1)->getText() == "1") { return BitComparisonExpression(comp_expr.expression(0)->getText(), false); } else { return BitComparisonExpression(comp_expr.expression(0)->getText(), true); } } } } return std::nullopt; } } // namespace namespace qcor { antlrcpp::Any qasm3_visitor::visitBranchingStatement( qasm3Parser::BranchingStatementContext* context) { Loading @@ -10,6 +65,18 @@ antlrcpp::Any qasm3_visitor::visitBranchingStatement( // Get the conditional expression auto conditional_expr = context->booleanExpression(); auto bit_check_conditional = tryParseSimpleBooleanExpression(*conditional_expr); // Currently, we're only support If (not else yet) auto meas_var = symbol_table.try_lookup_meas_result(bit_check_conditional->var_name); if (bit_check_conditional.has_value() && context->programBlock().size() == 1 && meas_var.has_value()) { std::cout << "This is a simple Measure check\n"; auto nisqIfStmt = builder.create<mlir::quantum::ConditionalOp>( location, meas_var.value()); } // Map it to a Value qasm3_expression_generator exp_generator(builder, symbol_table, file_name); exp_generator.visit(conditional_expr); Loading Loading
mlir/dialect/include/Quantum/QuantumOps.td +1 −1 Original line number Diff line number Diff line Loading @@ -238,7 +238,7 @@ def ConditionalOp : QuantumOp<"ifElseOp", []> { let summary = "if-then-else operation conditioned on a quantum Measure"; // Must be conditioned on a Result type let arguments = (ins ResultType:$result_bit); let results = (outs Variadic<AnyType>:$results); let results = (outs); let regions = (region SizedRegion<1>:$thenRegion, AnyRegion:$elseRegion); } Loading
mlir/parsers/qasm3/examples/measure_conditional.qasm 0 → 100644 +10 −0 Original line number Diff line number Diff line OPENQASM 3; include "qelib1.inc"; qubit q; bit c; h q; c = measure q; if (c) { x q; }
mlir/parsers/qasm3/utils/symbol_table.cpp +24 −0 Original line number Diff line number Diff line Loading @@ -144,4 +144,28 @@ void ScopedSymbolTable::evaluate_const_global(const std::string variable_name, // add_symbol(variable_name, x, {"const"}); return; } void ScopedSymbolTable::add_measure_bit_assignment( const mlir::Value &bit_var, const mlir::Value &result_var) { assert(result_var.getType().isa<mlir::OpaqueType>()); bit_var_ptr_to_meas_result_var[bit_var.getAsOpaquePointer()] = result_var; } std::optional<mlir::Value> ScopedSymbolTable::try_lookup_meas_result(const mlir::Value &bit_var) { const auto iter = bit_var_ptr_to_meas_result_var.find(bit_var.getAsOpaquePointer()); if (iter != bit_var_ptr_to_meas_result_var.end()) { return iter->second; } return std::nullopt; } std::optional<mlir::Value> ScopedSymbolTable::try_lookup_meas_result(const std::string &bit_var_name) { if (!has_symbol(bit_var_name)) { return std::nullopt; } return try_lookup_meas_result(get_symbol(bit_var_name)); } } // namespace qcor No newline at end of file
mlir/parsers/qasm3/utils/symbol_table.hpp +11 −1 Original line number Diff line number Diff line Loading @@ -138,6 +138,12 @@ class ScopedSymbolTable { // Map Opaque Ptr of value to key in SymbolTable std::map<void*, std::string> replacement_helper; // Map Opaque Ptr of bit value to the originating Result* (from measure) // Note: after Measure, we perform a casting from Result* -> bool. // This map tracks the Result* returns by the measure op // so that we can trace the originating Result*. std::unordered_map<void *, mlir::Value> bit_var_ptr_to_meas_result_var; public: template <typename T> T get_global_constant(const std::string variable_name) { Loading Loading @@ -425,6 +431,10 @@ class ScopedSymbolTable { return array_qubit_symbol_name(qreg_name, std::to_string(index)); } void add_measure_bit_assignment(const mlir::Value &bit_var, const mlir::Value &result_var); std::optional<mlir::Value> try_lookup_meas_result(const mlir::Value &bit_var); std::optional<mlir::Value> try_lookup_meas_result(const std::string &bit_var_name); ~ScopedSymbolTable() {} }; } // namespace qcor No newline at end of file
mlir/parsers/qasm3/visitor_handlers/conditional_handler.cpp +67 −0 Original line number Diff line number Diff line Loading @@ -2,6 +2,61 @@ #include "expression_handler.hpp" #include "qasm3_visitor.hpp" namespace { // ATM, we don't try to convert everything to the // special Quantum If-Then-Else Op. // Rather, we aim for very narrow use-case that we're sure // that this can be done. // i.e., this serve mainly as a stop-gap before fully-FTQC runtimes become // available. // Capture binary comparison conditional. // Note: currently, only bit-level is modeled. // (Some backends, e.g., Honeywell, support a richer set of comparison ops). struct BitComparisonExpression { std::string var_name; bool comparison_value; BitComparisonExpression(const std::string &var, bool val) : var_name(var), comparison_value(val) {} }; // Test if this is a simple bit check conditional: // e.g., // if (b) or if (b==1), etc. std::optional<BitComparisonExpression> tryParseSimpleBooleanExpression( qasm3Parser::BooleanExpressionContext &boolean_expr) { // std::cout << "conditional expr: " << boolean_expr.getText() << "\n"; if (boolean_expr.comparsionExpression()) { auto &comp_expr = *(boolean_expr.comparsionExpression()); if (comp_expr.expression().size() == 1) { return BitComparisonExpression(comp_expr.expression(0)->getText(), true); } if (comp_expr.expression().size() == 2 && comp_expr.relationalOperator()) { if (comp_expr.relationalOperator()->getText() == "==") { if (comp_expr.expression(1)->getText() == "1") { return BitComparisonExpression(comp_expr.expression(0)->getText(), true); } else { return BitComparisonExpression(comp_expr.expression(0)->getText(), false); } } if (comp_expr.relationalOperator()->getText() == "!=") { if (comp_expr.expression(1)->getText() == "1") { return BitComparisonExpression(comp_expr.expression(0)->getText(), false); } else { return BitComparisonExpression(comp_expr.expression(0)->getText(), true); } } } } return std::nullopt; } } // namespace namespace qcor { antlrcpp::Any qasm3_visitor::visitBranchingStatement( qasm3Parser::BranchingStatementContext* context) { Loading @@ -10,6 +65,18 @@ antlrcpp::Any qasm3_visitor::visitBranchingStatement( // Get the conditional expression auto conditional_expr = context->booleanExpression(); auto bit_check_conditional = tryParseSimpleBooleanExpression(*conditional_expr); // Currently, we're only support If (not else yet) auto meas_var = symbol_table.try_lookup_meas_result(bit_check_conditional->var_name); if (bit_check_conditional.has_value() && context->programBlock().size() == 1 && meas_var.has_value()) { std::cout << "This is a simple Measure check\n"; auto nisqIfStmt = builder.create<mlir::quantum::ConditionalOp>( location, meas_var.value()); } // Map it to a Value qasm3_expression_generator exp_generator(builder, symbol_table, file_name); exp_generator.visit(conditional_expr); Loading