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

NISQ QIR util to create a __qpu__ annotated function



This will make the TokenCollector aware of this kernel and insert parent_kernel as expected.

Fixed the token collector getting the wrong function name when there is a macro expansion to create the __qpu__ kernel.

Signed-off-by: default avatarThien Nguyen <nguyentm@ornl.gov>
parent 7ded333a
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -26,7 +26,7 @@ __qpu__ void qpe(qreg q, QPEOracleSignature oracle) {

  // Run Inverse QFT on counting qubits
  // Using the Q# Kernel (wrapped as a QCOR kernel)
  QCOR__IQFT(parent_kernel, counting_qubits);
  QCOR__IQFT(counting_qubits);

  // Measure the counting qubits
  Measure(counting_qubits);
+3 −2
Original line number Diff line number Diff line
@@ -40,8 +40,9 @@ void QCORSyntaxHandler::GetReplacement(Preprocessor &PP, Declarator &D,

    auto type = QualType::getAsString(parm_var_decl->getType().split(),
                                      PrintingPolicy{{}});
    auto var = PP.getSpelling(IdentToken);

    // auto var = PP.getSpelling(IdentToken);
    // Using IdentifierInfo to get the correct name (after any macro expansion)
    auto var = ident->getName().str();
    if (type == "class xacc::internal_compiler::qreg") {
      bufferNames.push_back(ident->getName().str());
      type = "qreg";
+29 −110
Original line number Diff line number Diff line
@@ -46,127 +46,46 @@
            qcor_import_qsharp_kernel_no_var, unknown)                         \
  (__VA_ARGS__)

// Note: By convention, the Q# LLVM func name has the __body suffix:
// Strategy: define a __qpu__ function which call the LLVM func.
#define qcor_import_qsharp_kernel_var(OPERATION_NAME, ...)                     \
  extern "C" void OPERATION_NAME##__body(::Array *, __VA_ARGS__);              \
  class OPERATION_NAME                                                         \
      : public qcor::QuantumKernel<class OPERATION_NAME, qreg, __VA_ARGS__> {  \
  private:                                                                     \
    ::Array *m_qubits = nullptr;                                               \
    friend class qcor::QuantumKernel<class OPERATION_NAME, qreg, __VA_ARGS__>; \
    friend class qcor::KernelSignature<qreg, __VA_ARGS__>;                     \
                                                                               \
  protected:                                                                   \
    void operator()(qreg q ARGS_LIST_FOR_FUNC_SIGNATURE(__VA_ARGS__)) {        \
      if (!parent_kernel) {                                                    \
        parent_kernel = qcor::__internal__::create_composite(kernel_name);     \
      }                                                                        \
      quantum::set_current_program(parent_kernel);                             \
      if (runtime_env == QrtType::FTQC) {                                      \
        quantum::set_current_buffer(q.results());                              \
      }                                                                        \
      /* Convert the qreg to QIR Array of Qubits */                            \
      if (!m_qubits) {                                                         \
        m_qubits = new ::Array(q.size());                                      \
  __qpu__ void OPERATION_NAME(                                                 \
      qreg q ARGS_LIST_FOR_FUNC_SIGNATURE(__VA_ARGS__)) {                      \
    auto m_qubits = new ::Array(q.size());                                     \
    for (int i = 0; i < q.size(); ++i) {                                       \
      auto qubit = Qubit::create(q[i].second);                                 \
      int8_t *arrayPtr = (*m_qubits)[i];                                       \
      auto qubitPtr = reinterpret_cast<Qubit **>(arrayPtr);                    \
          *qubitPtr = qubit;                                                   \
        }                                                                      \
      }                                                                        \
      OPERATION_NAME##__body(m_qubits ARGS_LIST_FOR_FUNC_INVOKE(               \
          __VA_ARGS__)); /* std::cout << "INVOKE:\n" <<                        \
                            parent_kernel->toString(); */                      \
    }                                                                          \
                                                                               \
  public:                                                                      \
    inline static const std::string kernel_name = #OPERATION_NAME;             \
    OPERATION_NAME(qreg q ARGS_LIST_FOR_FUNC_SIGNATURE(__VA_ARGS__))           \
        : QuantumKernel<OPERATION_NAME, qreg, __VA_ARGS__>(                    \
              q ARGS_LIST_FOR_FUNC_INVOKE(__VA_ARGS__)) {}                     \
    OPERATION_NAME(std::shared_ptr<qcor::CompositeInstruction> _parent,        \
                   qreg q ARGS_LIST_FOR_FUNC_SIGNATURE(__VA_ARGS__))           \
        : QuantumKernel<OPERATION_NAME, qreg, __VA_ARGS__>(                    \
              _parent, q ARGS_LIST_FOR_FUNC_INVOKE(__VA_ARGS__)) {}            \
    virtual ~OPERATION_NAME() {                                                \
      if (disable_destructor) {                                                \
        return;                                                                \
      (*qubitPtr) = qubit;                                                     \
    }                                                                          \
      auto [q ARGS_LIST_FOR_FUNC_INVOKE(__VA_ARGS__)] = args_tuple;            \
      operator()(q ARGS_LIST_FOR_FUNC_INVOKE(__VA_ARGS__));                    \
      xacc::internal_compiler::execute_pass_manager();                         \
      if (is_callable) {                                                       \
        quantum::submit(q.results());                                          \
      }                                                                        \
    }                                                                          \
  };                                                                           \
  void OPERATION_NAME(qreg q ARGS_LIST_FOR_FUNC_SIGNATURE(__VA_ARGS__)) {      \
    class OPERATION_NAME kernel(q ARGS_LIST_FOR_FUNC_INVOKE(__VA_ARGS__));     \
    OPERATION_NAME##__body(m_qubits ARGS_LIST_FOR_FUNC_INVOKE(__VA_ARGS__));   \
    delete m_qubits;                                                           \
  }

#define qcor_import_qsharp_kernel_no_var(OPERATION_NAME)                       \
  extern "C" void OPERATION_NAME##__body(::Array *);                           \
  class OPERATION_NAME                                                         \
      : public qcor::QuantumKernel<class OPERATION_NAME, qreg> {               \
  private:                                                                     \
    ::Array *m_qubits = nullptr;                                               \
    friend class qcor::QuantumKernel<class OPERATION_NAME, qreg>;              \
    friend class qcor::KernelSignature<qreg>;                                  \
                                                                               \
  protected:                                                                   \
    void operator()(qreg q) {                                                  \
      if (!parent_kernel) {                                                    \
        /* std::cout << "Create parent kernel\n";   */                         \
        parent_kernel = qcor::__internal__::create_composite(kernel_name);     \
      }                                                                        \
      /* std::cout << "Parent:\n" << parent_kernel->toString() << "\n";  */    \
      quantum::set_current_program(parent_kernel);                             \
      if (runtime_env == QrtType::FTQC) {                                      \
        quantum::set_current_buffer(q.results());                              \
      }                                                                        \
      /* Convert the qreg to QIR Array of Qubits */                            \
      if (!m_qubits) {                                                         \
        m_qubits = new ::Array(q.size());                                      \
  __qpu__ void OPERATION_NAME(qreg q) {                                        \
    auto m_qubits = new ::Array(q.size());                                     \
    for (int i = 0; i < q.size(); ++i) {                                       \
      auto qubit = Qubit::create(q[i].second);                                 \
      int8_t *arrayPtr = (*m_qubits)[i];                                       \
      auto qubitPtr = reinterpret_cast<Qubit **>(arrayPtr);                    \
          *qubitPtr = qubit;                                                   \
      (*qubitPtr) = qubit;                                                     \
    }                                                                          \
      }                                                                        \
      /*std::cout << "INVOKE:\n" << parent_kernel->toString() << "\n";  */     \
      OPERATION_NAME##__body(m_qubits); /* std::cout << "INVOKE:\n" <<         \
                            parent_kernel->toString(); */                      \
    }                                                                          \
                                                                               \
  public:                                                                      \
    inline static const std::string kernel_name = #OPERATION_NAME;             \
    OPERATION_NAME(qreg q) : QuantumKernel<OPERATION_NAME, qreg>(q) {}         \
    OPERATION_NAME(std::shared_ptr<qcor::CompositeInstruction> _parent,        \
                   qreg q)                                                     \
        : QuantumKernel<OPERATION_NAME, qreg>(_parent, q) {}                   \
    virtual ~OPERATION_NAME() {                                                \
      if (disable_destructor) {                                                \
        return;                                                                \
      }                                                                        \
      auto [q] = args_tuple;                                                   \
      /* std::cout << "here\n";   */                                           \
      operator()(q);                                                           \
      xacc::internal_compiler::execute_pass_manager();                         \
      if (is_callable) {                                                       \
        quantum::submit(q.results());                                          \
      }                                                                        \
    }                                                                          \
  };                                                                           \
  void OPERATION_NAME(std::shared_ptr<qcor::CompositeInstruction> parent,      \
                      qreg q) {                                                \
    class OPERATION_NAME kernel(parent, q);                                    \
  }                                                                            \
  void OPERATION_NAME(qreg q) { class OPERATION_NAME kernel(q); }

    OPERATION_NAME##__body(m_qubits);                                          \
    delete m_qubits;                                                           \
  }
// Usage:
// qcor_import_qsharp_kernel(MyQsharpKernel, double, int);
// This will inject a QCOR kernel of signature:
// void MyQsharpKernel(qreg, double, int);
// which can be used in QCOR, e.g. supporting NISQ remote submit API
// and runtime pass manager, etc.

// LIMITATIONS:
// - Multiple qreg arguments are not supported: i.e. qreg can only be the first
// argument.
// - Argument translation is not currently supported: i.e. can only handle
// simple types: int, double; not vectors.
// - Max number of arguments: 8 (add more macros if needed)
 No newline at end of file