Loading mlir/parsers/qasm3/tests/test_control_directives.cpp +111 −4 Original line number Diff line number Diff line Loading @@ -223,7 +223,6 @@ QCOR_EXPECT_TRUE(val2 == 3); EXPECT_FALSE(qcor::execute(uint_index, "uint_index")); } TEST(qasm3VisitorTester, checkEarlyReturnNestedLoop) { const std::string uint_index = R"#(OPENQASM 3; include "qelib1.inc"; Loading Loading @@ -278,6 +277,115 @@ QCOR_EXPECT_TRUE(val == 3); EXPECT_FALSE(qcor::execute(uint_index, "uint_index")); } // Nesting for and while loops TEST(qasm3VisitorTester, checkEarlyReturnNestedWhileLoop) { const std::string uint_index = R"#(OPENQASM 3; include "qelib1.inc"; def generate_number(int[64]: break_value, int[64]: max_run) -> int[64] { int[64] run_count = 0; int[64] i = 0; while(run_count < max_run) { for j in [0:10] { run_count += 1; if (i == j && i > break_value) { print("Return at i = ", i); print("Return at j = ", j); return run_count; } print("i =", i); print("j =", j); } i += 1; print("Out of inner loop"); } print("make it to the end"); return 0; } // Case 1: early return @ (i == j && i > break_value) // => 23 runs (return run_count in this path) int[64] val = generate_number(1, 100); print("Result =", val); QCOR_EXPECT_TRUE(val == 23); // Case 2: return at the end // Make it to the end since run_count will hit 20 // before hitting the early return condition. val = generate_number(1, 20); print("Result =", val); QCOR_EXPECT_TRUE(val == 0); )#"; auto mlir = qcor::mlir_compile(uint_index, "uint_index", qcor::OutputType::MLIR, false); std::cout << mlir << "\n"; EXPECT_FALSE(qcor::execute(uint_index, "uint_index")); } // Test a complex construction with nesting of different loop types, // break, return, etc... TEST(qasm3VisitorTester, checkControlDirectiveKitchenSink) { const std::string uint_index = R"#(OPENQASM 3; include "qelib1.inc"; def find_number(int[64]: target, int[64]: max_run) -> int[64] { int[64] run_count = 0; for i in { 1, 3, 5, 7, 9} { while(run_count < max_run) { for j in [0:10] { run_count += 1; if (i == target && j == i) { print("Return at i = ", i); print("Return at j = ", j); print("Return run_count = ", run_count); return run_count; } print("i =", i); print("j =", j); } // Finish the searching [0->10], break the while loop // This is a weird construction, // just for testing. break; } print("Make it out of the loop"); print("run_count = ", run_count); } print("Not found"); return 0; } int[64] val = find_number(3, 100); print("Result =", val); // Find number 3 at 14 iterations. QCOR_EXPECT_TRUE(val == 14); val = find_number(2, 100); print("Result =", val); // Cannot find number 2 in the set: QCOR_EXPECT_TRUE(val == 0); val = find_number(7, 20); print("Result =", val); // Cannot find number 7 with only 20 iterations QCOR_EXPECT_TRUE(val == 0); val = find_number(7, 100); print("Result =", val); // But will find it at iteration 38... QCOR_EXPECT_TRUE(val == 38); )#"; auto mlir = qcor::mlir_compile(uint_index, "uint_index", qcor::OutputType::MLIR, false); std::cout << mlir << "\n"; EXPECT_FALSE(qcor::execute(uint_index, "uint_index")); } TEST(qasm3VisitorTester, checkIqpewithIf) { const std::string qasm_code = R"#(OPENQASM 3; include "qelib1.inc"; Loading Loading @@ -359,14 +467,13 @@ QCOR_EXPECT_TRUE(c[3] == 1); )#"; // Make sure we can compile this in FTQC. // i.e., usual if ... auto mlir = qcor::mlir_compile(qasm_code, "iqpe", qcor::OutputType::LLVMIR, false); auto mlir = qcor::mlir_compile(qasm_code, "iqpe", qcor::OutputType::LLVMIR, false); std::cout << mlir << "\n"; // Execute (FTQC + optimization): validate expected results: 1101 EXPECT_FALSE(qcor::execute(qasm_code, "iqpe")); } int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); auto ret = RUN_ALL_TESTS(); Loading mlir/parsers/qasm3/visitor_handlers/loop_stmt_handler.cpp +7 −7 Original line number Diff line number Diff line Loading @@ -508,7 +508,6 @@ void qasm3_visitor::createWhileLoop( auto loop_signature = context->loopSignature(); auto program_block = context->programBlock(); assert(loop_signature->booleanExpression()); auto main_block = builder.saveInsertionPoint(); auto cachedBuilder = builder; // Check if the loop is break-able (contains control directive node) Loading Loading @@ -619,14 +618,15 @@ void qasm3_visitor::createWhileLoop( } builder = cachedBuilder; // Handle potential return statement in the loop. handleReturnInLoop(location); // 'After' block must end with a yield op. { mlir::OpBuilder::InsertionGuard g(builder); mlir::Operation &lastOp = whileOp.after().front().getOperations().back(); builder.setInsertionPointAfter(&lastOp); builder.create<mlir::scf::YieldOp>(location); builder.restoreInsertionPoint(main_block); } // Handle potential return statement in the loop. handleReturnInLoop(location); } } // namespace qcor No newline at end of file Loading
mlir/parsers/qasm3/tests/test_control_directives.cpp +111 −4 Original line number Diff line number Diff line Loading @@ -223,7 +223,6 @@ QCOR_EXPECT_TRUE(val2 == 3); EXPECT_FALSE(qcor::execute(uint_index, "uint_index")); } TEST(qasm3VisitorTester, checkEarlyReturnNestedLoop) { const std::string uint_index = R"#(OPENQASM 3; include "qelib1.inc"; Loading Loading @@ -278,6 +277,115 @@ QCOR_EXPECT_TRUE(val == 3); EXPECT_FALSE(qcor::execute(uint_index, "uint_index")); } // Nesting for and while loops TEST(qasm3VisitorTester, checkEarlyReturnNestedWhileLoop) { const std::string uint_index = R"#(OPENQASM 3; include "qelib1.inc"; def generate_number(int[64]: break_value, int[64]: max_run) -> int[64] { int[64] run_count = 0; int[64] i = 0; while(run_count < max_run) { for j in [0:10] { run_count += 1; if (i == j && i > break_value) { print("Return at i = ", i); print("Return at j = ", j); return run_count; } print("i =", i); print("j =", j); } i += 1; print("Out of inner loop"); } print("make it to the end"); return 0; } // Case 1: early return @ (i == j && i > break_value) // => 23 runs (return run_count in this path) int[64] val = generate_number(1, 100); print("Result =", val); QCOR_EXPECT_TRUE(val == 23); // Case 2: return at the end // Make it to the end since run_count will hit 20 // before hitting the early return condition. val = generate_number(1, 20); print("Result =", val); QCOR_EXPECT_TRUE(val == 0); )#"; auto mlir = qcor::mlir_compile(uint_index, "uint_index", qcor::OutputType::MLIR, false); std::cout << mlir << "\n"; EXPECT_FALSE(qcor::execute(uint_index, "uint_index")); } // Test a complex construction with nesting of different loop types, // break, return, etc... TEST(qasm3VisitorTester, checkControlDirectiveKitchenSink) { const std::string uint_index = R"#(OPENQASM 3; include "qelib1.inc"; def find_number(int[64]: target, int[64]: max_run) -> int[64] { int[64] run_count = 0; for i in { 1, 3, 5, 7, 9} { while(run_count < max_run) { for j in [0:10] { run_count += 1; if (i == target && j == i) { print("Return at i = ", i); print("Return at j = ", j); print("Return run_count = ", run_count); return run_count; } print("i =", i); print("j =", j); } // Finish the searching [0->10], break the while loop // This is a weird construction, // just for testing. break; } print("Make it out of the loop"); print("run_count = ", run_count); } print("Not found"); return 0; } int[64] val = find_number(3, 100); print("Result =", val); // Find number 3 at 14 iterations. QCOR_EXPECT_TRUE(val == 14); val = find_number(2, 100); print("Result =", val); // Cannot find number 2 in the set: QCOR_EXPECT_TRUE(val == 0); val = find_number(7, 20); print("Result =", val); // Cannot find number 7 with only 20 iterations QCOR_EXPECT_TRUE(val == 0); val = find_number(7, 100); print("Result =", val); // But will find it at iteration 38... QCOR_EXPECT_TRUE(val == 38); )#"; auto mlir = qcor::mlir_compile(uint_index, "uint_index", qcor::OutputType::MLIR, false); std::cout << mlir << "\n"; EXPECT_FALSE(qcor::execute(uint_index, "uint_index")); } TEST(qasm3VisitorTester, checkIqpewithIf) { const std::string qasm_code = R"#(OPENQASM 3; include "qelib1.inc"; Loading Loading @@ -359,14 +467,13 @@ QCOR_EXPECT_TRUE(c[3] == 1); )#"; // Make sure we can compile this in FTQC. // i.e., usual if ... auto mlir = qcor::mlir_compile(qasm_code, "iqpe", qcor::OutputType::LLVMIR, false); auto mlir = qcor::mlir_compile(qasm_code, "iqpe", qcor::OutputType::LLVMIR, false); std::cout << mlir << "\n"; // Execute (FTQC + optimization): validate expected results: 1101 EXPECT_FALSE(qcor::execute(qasm_code, "iqpe")); } int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); auto ret = RUN_ALL_TESTS(); Loading
mlir/parsers/qasm3/visitor_handlers/loop_stmt_handler.cpp +7 −7 Original line number Diff line number Diff line Loading @@ -508,7 +508,6 @@ void qasm3_visitor::createWhileLoop( auto loop_signature = context->loopSignature(); auto program_block = context->programBlock(); assert(loop_signature->booleanExpression()); auto main_block = builder.saveInsertionPoint(); auto cachedBuilder = builder; // Check if the loop is break-able (contains control directive node) Loading Loading @@ -619,14 +618,15 @@ void qasm3_visitor::createWhileLoop( } builder = cachedBuilder; // Handle potential return statement in the loop. handleReturnInLoop(location); // 'After' block must end with a yield op. { mlir::OpBuilder::InsertionGuard g(builder); mlir::Operation &lastOp = whileOp.after().front().getOperations().back(); builder.setInsertionPointAfter(&lastOp); builder.create<mlir::scf::YieldOp>(location); builder.restoreInsertionPoint(main_block); } // Handle potential return statement in the loop. handleReturnInLoop(location); } } // namespace qcor No newline at end of file