Commit 633d0551 authored by Mccaskey, Alex's avatar Mccaskey, Alex
Browse files

general cleanup, fixed bug in obj operator()

parent fafc6a92
Loading
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -90,7 +90,7 @@ public:
    // Get Tokens as a string, rewrite code
    // with XACC api calls

    auto new_src = qcor::run_token_collector(PP, Toks, bufferNames, function_prototype );
    auto new_src = qcor::run_token_collector(PP, Toks, bufferNames);

    OS << "quantum::initialize(\"" << qpu_name << "\", \"" << kernel_name
       << "\");\n";
+4 −5
Original line number Diff line number Diff line
@@ -21,8 +21,7 @@ TEST(TokenCollectorTester, checkSimple) {
    cached.push_back(t);
  }

  auto results = qcor::run_token_collector(*PP, cached, {"q"},
                                           "void foo(qreg q, double theta)");
  auto results = qcor::run_token_collector(*PP, cached, {"q"});

  std::cout << results << "\n";
}
@@ -67,7 +66,7 @@ TEST(TokenCollectorTester, checkQPE) {
    cached.push_back(t);
  }
  auto results =
      qcor::run_token_collector(*PP, cached, {"q"}, "void qpe(qreg q)");
      qcor::run_token_collector(*PP, cached, {"q"});
  std::cout << results << "\n";
}

@@ -86,7 +85,7 @@ TEST(TokenCollectorTester, checkOpenQasm) {
    cached.push_back(t);
  }
  auto results =
      qcor::run_token_collector(*PP, cached, {"r"}, "void bell(qreg r)");
      qcor::run_token_collector(*PP, cached, {"r"});
  std::cout << results << "\n";

  EXPECT_EQ(R"#(quantum::h(r[0]);
@@ -122,7 +121,7 @@ TEST(TokenCollectorTester, checkMixed) {
    cached.push_back(t);
  }
  auto results =
      qcor::run_token_collector(*PP, cached, {"r"}, "void bell(qreg r)");
      qcor::run_token_collector(*PP, cached, {"r"});
  std::cout << results << "\n";

  EXPECT_EQ(R"#(quantum::h(q[0]);
+1 −600
Original line number Diff line number Diff line
@@ -18,8 +18,7 @@ void info(const std::string &s) { xacc::info(s); }

std::string run_token_collector(clang::Preprocessor &PP,
                                clang::CachedTokens &Toks,
                                std::vector<std::string> bufferNames,
                                const std::string &function_prototype) {
                                std::vector<std::string> bufferNames) {

  if (!xacc::isInitialized()) {
    xacc::Initialize();
@@ -49,7 +48,6 @@ std::string run_token_collector(clang::Preprocessor &PP,
        i += 4;
      }

      std::cout << "LANG NAME: " << lang_name << "\n";
      if (lang_name == "openqasm") {
        lang_name = "staq";
      }
@@ -72,601 +70,4 @@ std::string run_token_collector(clang::Preprocessor &PP,
  return code_ss.str();
}

void run_token_collector_llvm_rt(clang::Preprocessor &PP,
                                 clang::CachedTokens &Toks,
                                 const std::string &function_prototype,
                                 std::vector<std::string> bufferNames,
                                 const std::string &kernel_name,
                                 llvm::raw_string_ostream &OS,
                                 const std::string &qpu_name, int shots) {

  if (!xacc::isInitialized()) {
    xacc::Initialize();
  }

  // Used to have xasm return "", now " " needed
  // everywhere, being lazy here...
  auto add_spacing = [](const std::string language) {
    // if (language == "xasm") {
    //   return " ";
    // } else {
    return " ";
    // }
  };

  std::vector<std::pair<std::string, std::string>> classical_variables;

  // Programmers can specify the language by saying
  // using qcor::openqasm or something like that, default is xasm
  auto process_inst_stmt = [&](int &i, std::shared_ptr<xacc::Compiler> compiler,
                               clang::Token &current_token,
                               std::string &terminating_char,
                               std::string extra_preamble = "")
      -> std::pair<std::shared_ptr<xacc::Instruction>, std::string> {
    std::stringstream ss;
    auto current_token_str = PP.getSpelling(current_token);

    ss << extra_preamble;

    while (current_token_str != terminating_char) {
      ss << current_token_str << add_spacing(compiler->name());
      i++;
      current_token = Toks[i];
      current_token_str = PP.getSpelling(current_token);
    }

    if (ss.str().find("oracle") == std::string::npos) {
      ss << terminating_char;
    }

    // I want to store all classical variables, bc I need
    // to add them to the xacc kernel function prototype to
    // ensure canParse passes in certain cases
    if (ss.str().find("=") != std::string::npos) {
      // we have a classical var_type_tokens var_name = ...;
      int tmp_i = i;
      for (int j = tmp_i;; j--) {
        auto tok = Toks[j];
        if (tok.is(clang::tok::equal)) {
          auto var_name = PP.getSpelling(Toks[j - 1]);
          // get the var_type, which should be all
          // tokens back to last semi, l_brace, or r_brace, or if j == 0
          std::vector<std::string> tokens;
          for (int k = j - 2; k >= 0; k--) {
            if (Toks[k].is(clang::tok::semi) ||
                Toks[k].is(clang::tok::r_brace) ||
                Toks[k].is(clang::tok::l_brace)) {
              break;
            }
            if (PP.getSpelling(Toks[k]) != "const") {
              tokens.push_back(PP.getSpelling(Toks[k]));
            }
          }
          // reverse the tokens now and write them to
          // a string stream
          std::reverse(tokens.begin(), tokens.end());
          std::stringstream type_ss;
          for (auto &t : tokens) {
            type_ss << t;
          }
          auto var_type = type_ss.str();
          classical_variables.push_back({var_type, var_name});
          break;
        }
      }
    }

    auto tmp_func_proto = function_prototype;
    if (!classical_variables.empty()) {
      for (auto &[type, name] : classical_variables) {
        tmp_func_proto.insert(tmp_func_proto.length() - 1,
                              "," + type + " " + name);
      }
    }
    auto str_src = "__qpu__ " + tmp_func_proto + "{\n" + ss.str() + "\n}";

    // std::cout << "COMPILING\n"
    //           << tmp_func_proto + "{\n" + ss.str() + "\n}"
    //           << "\n";

    // If canParse, get the CompositeInst, if not, return the code
    // to be added to qrt_code
    if (compiler->canParse(str_src)) {
      return {compiler->compile(str_src)->getComposites()[0], ""};
    } else {
      return {nullptr, ss.str() + "\n"};
    }
  };

  std::function<void(int &, std::shared_ptr<xacc::Compiler>, clang::Token &,
                     clang::CachedTokens &, std::string &, std::stringstream &,
                     std::string)>
      process_for_block = [&](int &i, std::shared_ptr<xacc::Compiler> compiler,
                              clang::Token &current_token,
                              clang::CachedTokens &Toks,
                              std::string &terminating_char,
                              std::stringstream &qrt_code,
                              std::string extra_preamble) {
        // slurp up the for
        std::stringstream for_ss;

        // eat up the l_paren
        for_ss << "for (";
        int seen_l_paren = 1;
        i += 2;
        current_token = Toks[i];

        while (seen_l_paren > 0) {
          if (current_token.is(clang::tok::l_paren))
            seen_l_paren++;
          if (current_token.is(clang::tok::r_paren))
            seen_l_paren--;
          for_ss << PP.getSpelling(current_token) << " ";
          i++;
          current_token = Toks[i];
        }

        qrt_code << for_ss.str();
        // we could have for stmt with l_brace or without for a single inst
        if (current_token.is(clang::tok::l_brace)) {
          qrt_code << " {\n";

          // eat up the {
          i++;
          current_token = Toks[i];

          // Now loop through the for loop body
          int l_brace_count = 1;
          while (l_brace_count != 0) {
            // In here we have statements separated by compiler terminator
            // (default ';')
            // Note could have nested for stmts...
            if (current_token.is(clang::tok::kw_for)) {
              process_for_block(i, compiler, current_token, Toks,
                                terminating_char, qrt_code, extra_preamble);
            } else {
              auto [comp_inst, src_str] = process_inst_stmt(
                  i, compiler, current_token, terminating_char, extra_preamble);
              if (comp_inst) {
                auto visitor = std::make_shared<qrt_mapper>(comp_inst->name());
                xacc::InstructionIterator iter(comp_inst);
                while (iter.hasNext()) {
                  auto next = iter.next();
                  next->accept(visitor);
                }
                qrt_code << visitor->get_new_src();
              } else {
                qrt_code << src_str;
              }
            }
            // missing ';', eat it up too
            i++;
            current_token = Toks[i];

            if (current_token.is(clang::tok::l_brace)) {
              l_brace_count++;
            }

            if (current_token.is(clang::tok::r_brace)) {
              l_brace_count--;
            }
          }

          qrt_code << "}\n";

        } else {
          // Here we don't have a l_brace, so we just have the one
          // quantum instruction

          qrt_code << "\n   ";

          auto [comp_inst, src_str] = process_inst_stmt(
              i, compiler, current_token, terminating_char, extra_preamble);
          if (comp_inst) {
            auto visitor = std::make_shared<qrt_mapper>(comp_inst->name());
            xacc::InstructionIterator iter(comp_inst);
            while (iter.hasNext()) {
              auto next = iter.next();
              next->accept(visitor);
            }
            qrt_code << visitor->get_new_src();
          } else {
            qrt_code << src_str;
          }
        }
      };

  auto compiler = xacc::getCompiler("xasm");
  auto terminating_char = compiler->get_statement_terminator();

  std::stringstream qrt_code;
  std::string extra_preamble = "", language = "xasm";
  std::map<std::string, std::string> oracle_name_to_extra_preamble;
  std::map<std::string, int> creg_name_to_size;
  int countQregs = 0;

  for (int i = 0; i < Toks.size(); i++) {
    auto current_token = Toks[i];
    auto current_token_str = PP.getSpelling(current_token);

    if (current_token.is(clang::tok::kw_using)) {
      // Found using
      // i+3 bc we skip using, qcor and ::;
      language = PP.getSpelling(Toks[i + 3]);
      if (language == "openqasm") {
        // use staq
        language = xacc::hasCompiler("staq") ? "staq" : "openqasm";

        std::stringstream sss;
        for (auto &b : bufferNames) {
          // sss << "qreg " << b << "[100];\n";
          // Note - we don't know the size of the buffer
          // at this point, so just create one with max size
          // and we can provide an IR Pass later that updates it
          auto q = qalloc(std::numeric_limits<int>::max());
          q.setNameAndStore(b.c_str());
        }
        extra_preamble += sss.str();
      }

      compiler = xacc::getCompiler(language);
      terminating_char = compiler->get_statement_terminator();
      // +4 to skip ';' too
      i = i + 4;
      continue;
    }

    if (current_token_str == "oracle") {
      if (language != "staq") {
        xacc::error("Error - must specify 'using qcor::openqasm;' before using "
                    "staq openqasm code.");
      }
      std::stringstream slurp_oracle;
      i++;
      current_token = Toks[i];
      std::string oracle_name = PP.getSpelling(current_token);
      slurp_oracle << "oracle " << oracle_name << " ";

      while (true) {

        i++;
        current_token = Toks[i];
        slurp_oracle << PP.getSpelling(current_token);

        if (current_token.is(clang::tok::r_brace)) {
          break;
        }
      }

      auto preamble = slurp_oracle.str() + "\n";

      oracle_name_to_extra_preamble.insert({oracle_name, preamble});
      continue;
    }

    if (oracle_name_to_extra_preamble.count(current_token_str)) {
      // add the appropriate preamble here
      extra_preamble += oracle_name_to_extra_preamble[current_token_str];
      auto [comp_inst, src_str] = process_inst_stmt(
          i, compiler, current_token, terminating_char, extra_preamble);
      if (comp_inst) {
        auto visitor = std::make_shared<qrt_mapper>(comp_inst->name());
        xacc::InstructionIterator iter(comp_inst);
        while (iter.hasNext()) {
          auto next = iter.next();
          next->accept(visitor);
        }
        qrt_code << visitor->get_new_src();
      } else {
        qrt_code << src_str;
      }
      continue;
    }

    if (current_token_str == "qreg") {

      // allocate called within kernel, likely with openqasm
      // get the size and allocated it, but dont add to kernel string

      // skip qreg
      i++;
      current_token = Toks[i];

      // get qreg var name
      auto variable_name = PP.getSpelling(current_token);

      // skip [
      i += 2;
      current_token = Toks[i];

      auto size = std::stoi(PP.getSpelling(current_token));

      // skip ] and ;
      i += 2;

      auto q = qalloc(size);
      q.setNameAndStore(variable_name.c_str());

      qrt_code << "auto " << variable_name << " = " << bufferNames[countQregs]
               << ";\n";

      classical_variables.push_back({"qreg", variable_name});
      countQregs++;

      continue;
    }

    if (current_token_str == "OPENQASM") {
      i += 2;
      continue;
    }

    if (current_token_str == "measure") {
      // we have an ibm style measure,
      // so make sure that we map to individual measures
      // since we don't know the size of the qreg

      // next token is qreg name
      i++;
      current_token = Toks[i];
      current_token_str = PP.getSpelling(current_token);
      auto qreg_name = current_token_str;

      // next token could be [ or could be ->
      i++;
      current_token = Toks[i];
      if (current_token.is(clang::tok::l_square)) {
        i--;
        i--;
        current_token = Toks[i];
        // This we can parse, so just eat it up and get the Measure IR node out
        auto [comp_inst, src_str] = process_inst_stmt(
            i, compiler, current_token, terminating_char, extra_preamble);
        if (comp_inst) {
          auto visitor = std::make_shared<qrt_mapper>(comp_inst->name());
          xacc::InstructionIterator iter(comp_inst);
          while (iter.hasNext()) {
            auto next = iter.next();
            next->accept(visitor);
          }
          qrt_code << visitor->get_new_src();
        } else {
          qrt_code << src_str;
        }
        continue;
      } else {
        // the token is ->

        // the next one is the creg name
        i++;
        current_token = Toks[i];
        current_token_str = PP.getSpelling(current_token);
        auto creg_name = current_token_str;
        auto size = creg_name_to_size[creg_name];
        for (int k = 0; k < size; k++) {
          qrt_code << "quantum::mz(" << qreg_name << "[" << k << "]);\n";
        }
        continue;
      }
    }

    if (current_token_str == "creg") {

      auto creg_name = PP.getSpelling(Toks[i + 1]);
      auto creg_size = PP.getSpelling(Toks[i + 3]);

      creg_name_to_size.insert({creg_name, std::stoi(creg_size)});

      std::stringstream sss;
      while (current_token.isNot(clang::tok::semi)) {
        sss << current_token_str << " ";
        i++;
        current_token = Toks[i];
        current_token_str = PP.getSpelling(current_token);
      }

      extra_preamble += sss.str() + ";\n";

      continue;
    }

    // If we find a for stmt...
    if (current_token.is(clang::tok::kw_for)) {

      process_for_block(i, compiler, current_token, Toks, terminating_char,
                        qrt_code, extra_preamble);
      //   std::cout << "out of for loop now, current is "
      //             << PP.getSpelling(current_token) << "\n";
      continue;
    }

    if (current_token.is(clang::tok::kw_if)) {
    }

    // this is a quantum statement + terminating char
    // slurp up to the terminating char
    auto [comp_inst, src_str] = process_inst_stmt(
        i, compiler, current_token, terminating_char, extra_preamble);
    if (comp_inst) {
      auto visitor = std::make_shared<qrt_mapper>(comp_inst->name());
      xacc::InstructionIterator iter(comp_inst);
      while (iter.hasNext()) {
        auto next = iter.next();
        next->accept(visitor);
      }
      qrt_code << visitor->get_new_src();
    } else {
      qrt_code << src_str;
    }
  }

  //   std::cout << "QRT CODE:\n" << qrt_code.str() << "\n";

  OS << "quantum::initialize(\"" << qpu_name << "\", \"" << kernel_name
     << "\");\n";
  for (auto &buf : bufferNames) {
    OS << buf << ".setNameAndStore(\"" + buf + "\");\n";
  }

  if (!oracle_name_to_extra_preamble.empty()) {
    // we had an oracle synthesis, just add an
    // anc registry preemptively
    OS << "auto anc = qalloc(" << std::numeric_limits<int>::max() << ");\n";
  }
  if (shots > 0) {
    OS << "quantum::set_shots(" << shots << ");\n";
  }
  OS << qrt_code.str();
  OS << "if (__execute) {\n";

  if (bufferNames.size() > 1) {
    OS << "xacc::AcceleratorBuffer * buffers[" << bufferNames.size() << "] = {";
    OS << bufferNames[0] << ".results()";
    for (unsigned int k = 1; k < bufferNames.size(); k++) {
      OS << ", " << bufferNames[k] << ".results()";
    }
    OS << "};\n";
    OS << "quantum::submit(buffers," << bufferNames.size();
  } else {
    OS << "quantum::submit(" << bufferNames[0] << ".results()";
  }

  OS << ");\n";
  OS << "}";

  // In runtime mode, we contribute each annotated *kernel* as a circuit.
  // Hence, kernels can be used within other kernels similar to the way
  // XACC circuits are instantiated in XASM.
  auto circuit = std::shared_ptr<xacc::Instruction>(
      new xacc::quantum::Circuit(kernel_name));
  xacc::contributeService(kernel_name, circuit);
}

} // namespace qcor

// FIXME may want this later
// if (current_token_str == "qreg") {

//   // allocate called within kernel, likely with openqasm
//   // get the size and allocated it, but dont add to kernel string

//   // skip qreg
//   i++;
//   current_token = Toks[i];

//   // get qreg var name
//   auto variable_name = PP.getSpelling(current_token);

//   // skip [
//   i += 2;
//   current_token = Toks[i];

//   std::cout << variable_name
//             << ", CURRENT: " << PP.getSpelling(current_token) << "\n";
//   auto size = std::stoi(PP.getSpelling(current_token));

//   // skip ] and ;
//   i += 2;
//   std::cout << "NOW WE ARE " << PP.getSpelling(Toks[i]) << "\n";

//   auto q = qalloc(size);
//   q.setNameAndStore(variable_name.c_str());

//   // Update function_prototype FIXME
//   continue;
// }

// slurp up the for
//   std::stringstream for_ss;

//   // eat up the l_paren
//   for_ss << "for (";
//   int seen_l_paren = 1;
//   i += 2;
//   current_token = Toks[i];

//   while (seen_l_paren > 0) {
//     if (current_token.is(clang::tok::l_paren))
//       seen_l_paren++;
//     if (current_token.is(clang::tok::r_paren))
//       seen_l_paren--;
//     for_ss << PP.getSpelling(current_token) << " ";
//     i++;
//     current_token = Toks[i];
//   }

//   qrt_code << for_ss.str();

//   // we could have for stmt with l_brace or without for a single inst
//   if (current_token.is(clang::tok::l_brace)) {
//     qrt_code << " {\n";

//     // eat up the {
//     i++;
//     current_token = Toks[i];

//     // Now loop through the for loop body
//     int l_brace_count = 1;
//     while (l_brace_count != 0) {
//       // In here we have statements separated by compiler terminator
//       // (default ';')
//       auto [comp_inst, src_str] = process_inst_stmt(
//           i, compiler, current_token, terminating_char,
//           extra_preamble);
//       {
//         auto visitor = std::make_shared<qrt_mapper>();
//         xacc::InstructionIterator iter(comp_inst);
//         while (iter.hasNext()) {
//           auto next = iter.next();
//           if (!next->isComposite()) {
//             next->accept(visitor);
//           }
//         }
//         // inst->accept(visitor);
//         qrt_code << visitor->get_new_src();
//       }
//       // missing ';', eat it up too
//       i++;
//       current_token = Toks[i];

//       if (current_token.is(clang::tok::l_brace)) {
//         l_brace_count++;
//       }

//       if (current_token.is(clang::tok::r_brace)) {
//         l_brace_count--;
//       }
//     }

//     // now eat the r_brace
//     i++;
//     // current_token = Toks[i];
//     qrt_code << "}\n";

//     continue;
//   } else {
//     // Here we don't have a l_brace, so we just have the one
//     // quantum instruction

//     qrt_code << "\n   ";

//     auto [comp_inst, src_str] = process_inst_stmt(
//         i, compiler, current_token, terminating_char, extra_preamble);
//     if (comp_inst) {
//       auto visitor = std::make_shared<qrt_mapper>();
//       xacc::InstructionIterator iter(comp_inst);
//       while (iter.hasNext()) {
//         auto next = iter.next();
//         if (!next->isComposite()) {
//           next->accept(visitor);
//         }
//       }
//       qrt_code << visitor->get_new_src();
//     } else {
//       qrt_code << src_str;
//     }

//     // missing ';', eat it up too
//     i++;
//     current_token = Toks[i];
//   }
 No newline at end of file
+1 −10
Original line number Diff line number Diff line
@@ -9,16 +9,7 @@ namespace qcor {

std::string run_token_collector(clang::Preprocessor &PP,
                                clang::CachedTokens &Toks,
                                std::vector<std::string> bufferNames,
                                const std::string &function_prototype);

void run_token_collector_llvm_rt(clang::Preprocessor &PP,
                                 clang::CachedTokens &Toks,
                                 const std::string &function_prototype,
                                 std::vector<std::string> bufferNames,
                                 const std::string &kernel_name,
                                 llvm::raw_string_ostream &OS,
                                 const std::string &qpu_name, int shots = 0);
                                std::vector<std::string> bufferNames);

void set_verbose(bool verbose);
void info(const std::string &s);
+2 −2
Original line number Diff line number Diff line
@@ -234,8 +234,6 @@ public:
          reinterpret_cast<void (*)(ArgumentTypes...)>(pointer_to_functor);
    }

    kernel = __internal__::kernel_as_composite_instruction(functor, args...);

    if (!qreg.results()) {
      // this hasn't been set, so set it
      qreg = std::get<0>(std::forward_as_tuple(args...));
@@ -243,6 +241,8 @@ public:

    if (kernel_is_xacc_composite) {
      kernel->updateRuntimeArguments(args...);
    } else {
      kernel = __internal__::kernel_as_composite_instruction(functor, args...);
    }
    return operator()();
  }