Commit e853ddd2 authored by Nguyen, Thien Minh's avatar Nguyen, Thien Minh
Browse files

Fixed a bug in single-qubit gate merge pass



Need to handle the case whereby the whole sequence is canceled, e.g. h-x-h-z, etc.

Signed-off-by: default avatarThien Nguyen <nguyentm@ornl.gov>
parent 314bacea
Loading
Loading
Loading
Loading
+42 −0
Original line number Diff line number Diff line
@@ -54,6 +54,48 @@ rz(2.4566) q[1];
  EXPECT_EQ(countSubstring(llvm, "__quantum__qis__rz"), 1);
}

TEST(qasm3PassManagerTester, checkSingleQubitGateMergeOpt) {
  // Merge to X == rx(pi)
  const std::string src = R"#(OPENQASM 3;
include "qelib1.inc";
qubit q[2];
h q[0];
z q[0];
h q[0];
)#";
  auto llvm =
      qcor::mlir_compile("qasm3", src, "test_kernel", qcor::OutputType::LLVMIR, false);
  std::cout << "LLVM:\n" << llvm << "\n";
  
  // Get the function LLVM only (not __internal_mlir_XXXX, etc.)
  llvm = llvm.substr(llvm.find("@test_kernel"));
  // 1 instrucions left: rx 
  EXPECT_EQ(countSubstring(llvm, "__quantum__qis"), 1);
  EXPECT_EQ(countSubstring(llvm, "__quantum__qis__rx"), 1);
}

TEST(qasm3PassManagerTester, checkRemoveUnusedQirCalls) {
  // Complete cancellation => remove extract and qalloc as well
  const std::string src = R"#(OPENQASM 3;
include "qelib1.inc";
qubit q[2];
h q[0];
z q[0];
h q[0];
x q[0];
cx q[0], q[1];
cx q[0], q[1];
)#";
  auto llvm =
      qcor::mlir_compile("qasm3", src, "test_kernel", qcor::OutputType::LLVMIR, false);
  std::cout << "LLVM:\n" << llvm << "\n";
  // No gates, extract, or alloc/dealloc:
  EXPECT_EQ(countSubstring(llvm, "__quantum__qis"), 0);
  EXPECT_EQ(countSubstring(llvm, "__quantum__rt__array_get_element_ptr_1d"), 0);
  EXPECT_EQ(countSubstring(llvm, "__quantum__rt__qubit_allocate_array"), 0);
  EXPECT_EQ(countSubstring(llvm, "__quantum__rt__qubit_release_array"), 0);
}

int main(int argc, char **argv) {
  ::testing::InitGoogleTest(&argc, argv);
  auto ret = RUN_ALL_TESTS();
+11 −3
Original line number Diff line number Diff line
@@ -133,9 +133,17 @@ void SingleQubitGateMergingPass::runOnOperation() {

        // Input -> Output mapping (this instruction is to be removed)
        auto last_inst_orig = ops_list.back();
        if (new_ops.empty()) {
          auto first_inst_orig = ops_list.front();
          // The new sequence is empty (complete cancellation)
          // Map input to output of the whole sequence.
          (*last_inst_orig.result_begin())
              .replaceAllUsesWith(first_inst_orig.getOperand(0));
        } else {
          auto last_inst_new = new_ops.back();
          (*last_inst_orig.result_begin())
              .replaceAllUsesWith(*last_inst_new.result_begin());
        }

        // Erase original instructions:
        for (auto &op_to_delete : ops_list) {