From d1dff5c25996c41963e44c4c89823dc09b465097 Mon Sep 17 00:00:00 2001 From: wongey <25296194+wongey@users.noreply.github.com> Date: Mon, 7 Jul 2025 17:08:23 -0400 Subject: [PATCH 01/18] Debug session with Narasinga --- src/cqiree/QireeManager.cc | 245 +++++++++++++++++++++++++++++++++++++ src/qiree/Module.cc | 30 +++++ src/qiree/Module.hh | 2 + 3 files changed, 277 insertions(+) create mode 100644 src/cqiree/QireeManager.cc diff --git a/src/cqiree/QireeManager.cc b/src/cqiree/QireeManager.cc new file mode 100644 index 0000000..4484ef1 --- /dev/null +++ b/src/cqiree/QireeManager.cc @@ -0,0 +1,245 @@ +//----------------------------------*-C++-*----------------------------------// +// Copyright 2025 UT-Battelle, LLC, and other QIR-EE developers. +// See the top-level COPYRIGHT file for details. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +//---------------------------------------------------------------------------// +//! \file cqiree/QireeManager.cc +//---------------------------------------------------------------------------// +#include "QireeManager.hh" + +#include +#include +#include + +#include "qiree_config.h" + +#include "qiree/Assert.hh" +#include "qiree/Executor.hh" +#include "qiree/Module.hh" +#include "qiree/QuantumInterface.hh" +#include "qiree/ResultDistribution.hh" +#include "qiree/SingleResultRuntime.hh" +#include "qirqsim/QsimQuantum.hh" +#include "qirqsim/QsimRuntime.hh" + +#define CQIREE_FAIL(CODE, MESSAGE) \ + do \ + { \ + std::cerr << "qiree failure: " << MESSAGE << '\n'; \ + return ReturnCode::CODE; \ + } while (0) + +namespace qiree +{ +//---------------------------------------------------------------------------// +QireeManager::QireeManager() = default; +QireeManager::~QireeManager() = default; + +//---------------------------------------------------------------------------// +QireeManager::ReturnCode +QireeManager::load_module(std::string_view data_contents) throw() +{ + try + { + // Convert string_view to string for Module constructor + std::string content{data_contents}; + module_ = Module::GetModule(content, false); + } + catch (std::exception const& e) + { + CQIREE_FAIL(fail_load, e.what()); + } + return ReturnCode::success; +} + +//---------------------------------------------------------------------------// +QireeManager::ReturnCode QireeManager::load_module(std::string filename) throw() +{ + try + { + module_ = std::make_unique(filename); + QIREE_ENSURE(*module_); + } + catch (std::exception const& e) + { + std::cerr << "qiree failure: " << e.what() << '\n'; + CQIREE_FAIL(fail_load, e.what()); + } + + return ReturnCode::success; +} + +//---------------------------------------------------------------------------// +QireeManager::ReturnCode QireeManager::num_quantum_reg(int& result) const + throw() +{ + if (!module_) + { + CQIREE_FAIL(not_ready, "cannot query module before module load"); + } + if (execute_) + { + CQIREE_FAIL(not_ready, "cannot query module after creating executor"); + } + + auto attrs = module_->load_entry_point_attrs(); + result = attrs.required_num_qubits; + return ReturnCode::success; +} + +//---------------------------------------------------------------------------// +QireeManager::ReturnCode QireeManager::num_classical_reg(int& result) const + throw() +{ + if (!module_) + { + CQIREE_FAIL(not_ready, "cannot query module before module load"); + } + if (execute_) + { + CQIREE_FAIL(not_ready, "cannot query module after creating executor"); + } + + auto attrs = module_->load_entry_point_attrs(); + result = attrs.required_num_results; + return ReturnCode::success; +} + +//---------------------------------------------------------------------------// +QireeManager::ReturnCode +QireeManager::setup_executor(std::string_view backend, + std::string_view config_json) throw() +{ + if (!module_) + { + CQIREE_FAIL(not_ready, "cannot create executor before module load"); + } + if (execute_) + { + CQIREE_FAIL(not_ready, "cannot create executor again"); + } + + try + { + if (!config_json.empty()) + { + QIREE_NOT_IMPLEMENTED("CQiree JSON configuration input"); + } + + if (backend == "qsim") + { +#if QIREE_USE_QSIM + // Create runtime interface: give runtime a pointer to quantum + // (lifetime of the reference is guaranteed by our shared pointer + // copy) + constexpr unsigned long int seed = 0; + auto quantum = std::make_shared(std::cout, seed); + runtime_ = std::make_shared(std::cout, *quantum); + quantum_ = std::move(quantum); +#else + QIREE_NOT_CONFIGURED("QSim"); +#endif + } + else if (backend == "xacc") + { +#if QIREE_USE_XACC + QIREE_NOT_IMPLEMENTED("XACC backend for CQiree"); +#else + QIREE_NOT_CONFIGURED("XACC"); +#endif + } + else + { + QIREE_VALIDATE(false, + << "unknown backend name '" << backend << "'"); + } + } + catch (std::exception const& e) + { + CQIREE_FAIL(fail_load, + "error while creating quantum runtimes: " << e.what()); + } + + try + { + // Create executor with the module, quantum and runtime interfaces + QIREE_ASSERT(module_ && *module_); + execute_ = std::make_unique(std::move(*module_)); + } + catch (std::exception const& e) + { + CQIREE_FAIL(fail_load, "error while creating executor: " << e.what()); + } + + return ReturnCode::success; +} + +//---------------------------------------------------------------------------// +QireeManager::ReturnCode QireeManager::execute(int num_shots) throw() +{ + if (execute_) + { + CQIREE_FAIL(not_ready, "cannot create executor again"); + } + + if (num_shots <= 0) + { + CQIREE_FAIL(invalid_input, "num_shots was nonpositive"); + } + + try + { + QIREE_ASSERT(runtime_ && quantum_); + result_ = std::make_unique(); + + for (auto i = 0; i < num_shots; ++i) + { + (*execute_)(*quantum_, *runtime_); + result_->accumulate(runtime_->result()); + } + } + catch (std::exception const& e) + { + CQIREE_FAIL(fail_execute, e.what()); + } + return ReturnCode::success; +} + +//---------------------------------------------------------------------------// +QireeManager::ReturnCode QireeManager::num_results(int& count) const throw() +{ + if (!result_) + { + CQIREE_FAIL(not_ready, "execute has not been called"); + } + + count = static_cast(result_->size()); + + return ReturnCode::success; +} + +//---------------------------------------------------------------------------// +QireeManager::ReturnCode +QireeManager::get_result(int index, std::string_view key, int* count) const + throw() +{ + if (!result_) + { + CQIREE_FAIL(not_ready, "execute has not been called"); + } + + try + { + (void)sizeof(key); + (void)sizeof(count); + QIREE_NOT_IMPLEMENTED("getting results"); + } + catch (std::exception const& e) + { + CQIREE_FAIL(fail_execute, + "could not retrieve index " << index << ": " << e.what()); + } + return ReturnCode::success; +} +//---------------------------------------------------------------------------// +} // namespace qiree diff --git a/src/qiree/Module.cc b/src/qiree/Module.cc index d771eb0..0308da8 100644 --- a/src/qiree/Module.cc +++ b/src/qiree/Module.cc @@ -15,6 +15,7 @@ #include #include #include +#include #include "Assert.hh" @@ -160,6 +161,35 @@ Module::~Module() = default; Module::Module(Module&&) = default; Module& Module::operator=(Module&&) = default; +std::unique_ptr Module::GetModule(std::string const & content, bool is_file) { + if (is_file) { + return std::make_unique(content); + } + else { + llvm::SMDiagnostic err; + //llvm::outs() << "Content:"< buffer = llvm::MemoryBuffer::getMemBuffer(content, "", false); + auto module = llvm::parseIR(buffer->getMemBufferRef(), err, context()); + if (!module) + { + err.print("qiree", llvm::errs()); + QIREE_VALIDATE(module, + << "failed to read QIR from the content '" << content << "'"); + } +#if 0 + llvm::outs() <<"Inside functions:\n"; + for (auto& func : module->functions()) { + llvm::outs() << "Function: "<(std::move(module)); + } +} + + //---------------------------------------------------------------------------// /*! * Process entry point attributes. diff --git a/src/qiree/Module.hh b/src/qiree/Module.hh index 21ed2df..75baf71 100644 --- a/src/qiree/Module.hh +++ b/src/qiree/Module.hh @@ -42,6 +42,8 @@ class Module Module(Module const&) = delete; Module& operator=(Module const&) = delete; + static std::unique_ptr GetModule(std::string const & content, bool is_file); + // Construct from an externally created LLVM module explicit Module(UPModule&& module); From 2f6f482d806b315e67f384b628ea03e5c8bcb4df Mon Sep 17 00:00:00 2001 From: wongey <25296194+wongey@users.noreply.github.com> Date: Mon, 14 Jul 2025 14:47:49 -0400 Subject: [PATCH 02/18] Update .gitignore for local files --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index 84c6635..6bb6a10 100644 --- a/.gitignore +++ b/.gitignore @@ -48,3 +48,8 @@ compile_commands.json cmake_install.cmake /CMakeCache.txt /CMakeFiles +.venv/ +*.sif +examples/others/qcut_circuit* +examples/others/pyqir_wamta_example.py +scripts/apptainers/qiree.sif \ No newline at end of file From 2b991a1f1049ab812a0ecfbe9a7f9981d3cb7bdb Mon Sep 17 00:00:00 2001 From: wongey <25296194+wongey@users.noreply.github.com> Date: Mon, 14 Jul 2025 15:09:22 -0400 Subject: [PATCH 03/18] Add module to parse in-memory LLVM IR string --- src/cqiree/QireeManager.cc | 5 ++-- src/qiree/Module.cc | 52 +++++++++++++++----------------------- src/qiree/Module.hh | 4 ++- 3 files changed, 26 insertions(+), 35 deletions(-) diff --git a/src/cqiree/QireeManager.cc b/src/cqiree/QireeManager.cc index 4484ef1..c792751 100644 --- a/src/cqiree/QireeManager.cc +++ b/src/cqiree/QireeManager.cc @@ -41,9 +41,8 @@ QireeManager::load_module(std::string_view data_contents) throw() { try { - // Convert string_view to string for Module constructor - std::string content{data_contents}; - module_ = Module::GetModule(content, false); + // Load module from memory contents + module_ = Module::UPModule::from_bytes(data_contents); } catch (std::exception const& e) { diff --git a/src/qiree/Module.cc b/src/qiree/Module.cc index 0308da8..b3ae965 100644 --- a/src/qiree/Module.cc +++ b/src/qiree/Module.cc @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -156,39 +157,28 @@ Module::Module(std::string const& filename, std::string const& entrypoint) } //---------------------------------------------------------------------------// -Module::Module() = default; -Module::~Module() = default; -Module::Module(Module&&) = default; -Module& Module::operator=(Module&&) = default; +/*! + * Reading a module by parsing an in-memory LLVM IR string. + */ -std::unique_ptr Module::GetModule(std::string const & content, bool is_file) { - if (is_file) { - return std::make_unique(content); - } - else { - llvm::SMDiagnostic err; - //llvm::outs() << "Content:"< buffer = llvm::MemoryBuffer::getMemBuffer(content, "", false); - auto module = llvm::parseIR(buffer->getMemBufferRef(), err, context()); - if (!module) - { - err.print("qiree", llvm::errs()); - QIREE_VALIDATE(module, - << "failed to read QIR from the content '" << content << "'"); - } -#if 0 - llvm::outs() <<"Inside functions:\n"; - for (auto& func : module->functions()) { - llvm::outs() << "Function: "<(std::move(module)); - } -} +Module::UPModule from_bytes(std::string_view content) { + llvm::SMDiagnostic err; + + // Create memory buffer from the in-memory IR content + auto buffer = llvm::MemoryBuffer::getMemBuffer(content, "", false); + // Parse the IR using LLVM context + auto llvm_module = llvm::parseIR(buffer->getMemBufferRef(), err, context()); + + if (!llvm_module) { + err.print("qiree", llvm::errs()); + QIREE_VALIDATE(llvm_module, + << "failed to parse QIR from in-memory content."); + } + + // Construct and return Module from parsed llvm::Module + return Module::UPModule(std::move(llvm_module)); +} //---------------------------------------------------------------------------// /*! diff --git a/src/qiree/Module.hh b/src/qiree/Module.hh index 75baf71..6e2b2a7 100644 --- a/src/qiree/Module.hh +++ b/src/qiree/Module.hh @@ -8,6 +8,7 @@ #pragma once #include +#include #include "Types.hh" @@ -42,7 +43,8 @@ class Module Module(Module const&) = delete; Module& operator=(Module const&) = delete; - static std::unique_ptr GetModule(std::string const & content, bool is_file); + // Reading a module by parsing an in-memory LLVM IR string. + static UPModule from_bytes(std::string_view content); // Construct from an externally created LLVM module explicit Module(UPModule&& module); From feb26409dd918cbd701b6634d349d8d3ec7e217a Mon Sep 17 00:00:00 2001 From: wongey <25296194+wongey@users.noreply.github.com> Date: Mon, 14 Jul 2025 15:12:00 -0400 Subject: [PATCH 04/18] Add test for from_bytes function --- test/Test.hh | 5 +++++ test/qiree/Module.test.cc | 22 ++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/test/Test.hh b/test/Test.hh index 5847f7c..82d064c 100644 --- a/test/Test.hh +++ b/test/Test.hh @@ -10,6 +10,11 @@ #include #include +#include +#include +#include +#include + namespace qiree { namespace test diff --git a/test/qiree/Module.test.cc b/test/qiree/Module.test.cc index 145661c..ef8b5b0 100644 --- a/test/qiree/Module.test.cc +++ b/test/qiree/Module.test.cc @@ -109,6 +109,28 @@ TEST_F(ModuleTest, several_gates) EXPECT_FALSE(flags.dynamic_result_management); } +//---------------------------------------------------------------------------// +TEST(ModuleTest, parse_ir_from_file) { + + // Helper function to read a file and return its contents as a string to be fed into from_bytes + auto read_ll_file = [](const std::string& path) -> std::string { + std::ifstream file(path); + if (!file) throw std::runtime_error("Cannot open file: " + path); + std::ostringstream buf; + buf << file.rdbuf(); + return buf.str(); + }; + + // Read the LLVM IR from a file and parse it + std::string ir = read_ll_file("bell.ll"); + std::string_view ir_view(ir); + + // Expect no exceptions during parsing + EXPECT_NO_THROW({ + Module m = Module::UPModule::from_bytes(ir_view); + }); +} + //---------------------------------------------------------------------------// } // namespace test } // namespace qiree From cb2f3d5fdaab63403998e2e2627dece2a639ce6d Mon Sep 17 00:00:00 2001 From: wongey <25296194+wongey@users.noreply.github.com> Date: Tue, 15 Jul 2025 07:00:36 -0400 Subject: [PATCH 05/18] Add link to build gtest with source if not found --- CMakeLists.txt | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index acfdb88..06f6331 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -174,9 +174,18 @@ endif() if(QIREE_BUILD_TESTS AND NOT GTest_FOUND) find_package(GTest) if(NOT GTest_FOUND) - message(SEND_ERROR - "Googletest (GTest) is required for testing but was not found" + message(STATUS "GTest not found, downloading latest version using FetchContent") + include(FetchContent) + # This declares version 1.17.0 of GTest, which is the latest stable (as of April 30, 2025) + FetchContent_Declare( + googletest + URL https://github.com/google/googletest/archive/04ee1b4f2aefdffb0135d7cf2a2c519fe50dabe4.zip ) + # For Windows: Prevent overriding the parent project's compiler/linker settings + set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) + FetchContent_MakeAvailable(googletest) + # Add GTest to the project + add_library(GTest::GTest ALIAS gtest) endif() endif() From ff92375a29c0f6d2ade4312af1bb2ff3349e7768 Mon Sep 17 00:00:00 2001 From: wongey <25296194+wongey@users.noreply.github.com> Date: Tue, 15 Jul 2025 11:55:45 -0400 Subject: [PATCH 06/18] Fix type errors --- src/cqiree/QireeManager.cc | 4 ++- src/qiree/Module.cc | 56 +++++++++++++++++++++++++++++--------- src/qiree/Module.hh | 2 +- test/qiree/Module.test.cc | 4 +-- 4 files changed, 49 insertions(+), 17 deletions(-) diff --git a/src/cqiree/QireeManager.cc b/src/cqiree/QireeManager.cc index c792751..7ab3c77 100644 --- a/src/cqiree/QireeManager.cc +++ b/src/cqiree/QireeManager.cc @@ -42,7 +42,9 @@ QireeManager::load_module(std::string_view data_contents) throw() try { // Load module from memory contents - module_ = Module::UPModule::from_bytes(data_contents); + std::string content{data_contents}; + // Convert string_view to string for Module constructor + module_ = Module::from_bytes(content, false); } catch (std::exception const& e) { diff --git a/src/qiree/Module.cc b/src/qiree/Module.cc index b3ae965..0746807 100644 --- a/src/qiree/Module.cc +++ b/src/qiree/Module.cc @@ -161,25 +161,55 @@ Module::Module(std::string const& filename, std::string const& entrypoint) * Reading a module by parsing an in-memory LLVM IR string. */ -Module::UPModule from_bytes(std::string_view content) { - llvm::SMDiagnostic err; +Module::Module() = default; +Module::~Module() = default; +Module::Module(Module&&) = default; +Module& Module::operator=(Module&&) = default; - // Create memory buffer from the in-memory IR content - auto buffer = llvm::MemoryBuffer::getMemBuffer(content, "", false); +std::unique_ptr Module::from_bytes(std::string const & content, bool is_file) { + if (is_file) { + return std::make_unique(content); + } + else { + llvm::SMDiagnostic err; + + // Create memory buffer from the in-memory IR content + std::unique_ptr buffer = llvm::MemoryBuffer::getMemBuffer(content, "", false); - // Parse the IR using LLVM context - auto llvm_module = llvm::parseIR(buffer->getMemBufferRef(), err, context()); + // Parse the IR using LLVM context + auto llvm_module = llvm::parseIR(buffer->getMemBufferRef(), err, context()); - if (!llvm_module) { - err.print("qiree", llvm::errs()); - QIREE_VALIDATE(llvm_module, - << "failed to parse QIR from in-memory content."); - } + if (!llvm_module) + { + err.print("qiree", llvm::errs()); + QIREE_VALIDATE(llvm_module, + << "Failed to parse QIR from in-memory content '" << content << "'"); + } - // Construct and return Module from parsed llvm::Module - return Module::UPModule(std::move(llvm_module)); + // Construct and return Module from parsed llvm::Module + return std::make_unique(std::move(llvm_module)); + } } + // Module::UPModule from_bytes(std::string_view content) { +// llvm::SMDiagnostic err; + +// // Create memory buffer from the in-memory IR content +// auto buffer = llvm::MemoryBuffer::getMemBuffer(content, "", false); + +// // Parse the IR using LLVM context +// auto llvm_module = llvm::parseIR(buffer->getMemBufferRef(), err, context()); + +// if (!llvm_module) { +// err.print("qiree", llvm::errs()); +// QIREE_VALIDATE(llvm_module, +// << "failed to parse QIR from in-memory content."); +// } + +// // Construct and return Module from parsed llvm::Module +// return Module::UPModule(std::move(llvm_module)); +// } + //---------------------------------------------------------------------------// /*! * Process entry point attributes. diff --git a/src/qiree/Module.hh b/src/qiree/Module.hh index 6e2b2a7..6e9a77e 100644 --- a/src/qiree/Module.hh +++ b/src/qiree/Module.hh @@ -44,7 +44,7 @@ class Module Module& operator=(Module const&) = delete; // Reading a module by parsing an in-memory LLVM IR string. - static UPModule from_bytes(std::string_view content); + static std::unique_ptr from_bytes(std::string const & content, bool is_file); // Construct from an externally created LLVM module explicit Module(UPModule&& module); diff --git a/test/qiree/Module.test.cc b/test/qiree/Module.test.cc index ef8b5b0..2c682cd 100644 --- a/test/qiree/Module.test.cc +++ b/test/qiree/Module.test.cc @@ -123,11 +123,11 @@ TEST(ModuleTest, parse_ir_from_file) { // Read the LLVM IR from a file and parse it std::string ir = read_ll_file("bell.ll"); - std::string_view ir_view(ir); + // std::string_view ir_view(ir); // Expect no exceptions during parsing EXPECT_NO_THROW({ - Module m = Module::UPModule::from_bytes(ir_view); + std::unique_ptr m = Module::from_bytes(ir, false); }); } From dba450fd403c3b9afa0fb57ffd2dcb480110ea1f Mon Sep 17 00:00:00 2001 From: wongey <25296194+wongey@users.noreply.github.com> Date: Tue, 15 Jul 2025 14:49:00 -0400 Subject: [PATCH 07/18] Require GTest and add instructions to build googletest locally --- CMakeLists.txt | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 06f6331..676abe7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -172,20 +172,11 @@ if(QIREE_BUILD_DOCS) endif() if(QIREE_BUILD_TESTS AND NOT GTest_FOUND) - find_package(GTest) + find_package(GTest REQUIRED) if(NOT GTest_FOUND) - message(STATUS "GTest not found, downloading latest version using FetchContent") - include(FetchContent) - # This declares version 1.17.0 of GTest, which is the latest stable (as of April 30, 2025) - FetchContent_Declare( - googletest - URL https://github.com/google/googletest/archive/04ee1b4f2aefdffb0135d7cf2a2c519fe50dabe4.zip + message(SEND_ERROR + "Googletest (GTest) is required for testing but was not found. Please install from source. Optional: In the user environment, you can run `cmake -DCMAKE_INSTALL_PREFIX=../install -DBUILD_SHARED_LIBS=ON ..` in the googletest/build folder, which allows you to build without sudo. Then you can set `export CMAKE_PREFIX_PATH=$HOME/googletest/install so that QIR-EE can find the installation." ) - # For Windows: Prevent overriding the parent project's compiler/linker settings - set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) - FetchContent_MakeAvailable(googletest) - # Add GTest to the project - add_library(GTest::GTest ALIAS gtest) endif() endif() From 22a648181020bdfc99f0b58ef26fdcdc3a48ead0 Mon Sep 17 00:00:00 2001 From: wongey <25296194+wongey@users.noreply.github.com> Date: Tue, 15 Jul 2025 14:53:45 -0400 Subject: [PATCH 08/18] Remove unncessary is_file variable and old non-working code --- src/cqiree/QireeManager.cc | 2 +- src/qiree/Module.cc | 26 +------------------------- src/qiree/Module.hh | 2 +- 3 files changed, 3 insertions(+), 27 deletions(-) diff --git a/src/cqiree/QireeManager.cc b/src/cqiree/QireeManager.cc index 7ab3c77..96bd2b8 100644 --- a/src/cqiree/QireeManager.cc +++ b/src/cqiree/QireeManager.cc @@ -44,7 +44,7 @@ QireeManager::load_module(std::string_view data_contents) throw() // Load module from memory contents std::string content{data_contents}; // Convert string_view to string for Module constructor - module_ = Module::from_bytes(content, false); + module_ = Module::from_bytes(content); } catch (std::exception const& e) { diff --git a/src/qiree/Module.cc b/src/qiree/Module.cc index 0746807..3456999 100644 --- a/src/qiree/Module.cc +++ b/src/qiree/Module.cc @@ -166,11 +166,7 @@ Module::~Module() = default; Module::Module(Module&&) = default; Module& Module::operator=(Module&&) = default; -std::unique_ptr Module::from_bytes(std::string const & content, bool is_file) { - if (is_file) { - return std::make_unique(content); - } - else { +std::unique_ptr Module::from_bytes(std::string const & content) { llvm::SMDiagnostic err; // Create memory buffer from the in-memory IR content @@ -188,28 +184,8 @@ std::unique_ptr Module::from_bytes(std::string const & content, bool is_ // Construct and return Module from parsed llvm::Module return std::make_unique(std::move(llvm_module)); - } } - // Module::UPModule from_bytes(std::string_view content) { -// llvm::SMDiagnostic err; - -// // Create memory buffer from the in-memory IR content -// auto buffer = llvm::MemoryBuffer::getMemBuffer(content, "", false); - -// // Parse the IR using LLVM context -// auto llvm_module = llvm::parseIR(buffer->getMemBufferRef(), err, context()); - -// if (!llvm_module) { -// err.print("qiree", llvm::errs()); -// QIREE_VALIDATE(llvm_module, -// << "failed to parse QIR from in-memory content."); -// } - -// // Construct and return Module from parsed llvm::Module -// return Module::UPModule(std::move(llvm_module)); -// } - //---------------------------------------------------------------------------// /*! * Process entry point attributes. diff --git a/src/qiree/Module.hh b/src/qiree/Module.hh index 6e9a77e..11d266a 100644 --- a/src/qiree/Module.hh +++ b/src/qiree/Module.hh @@ -44,7 +44,7 @@ class Module Module& operator=(Module const&) = delete; // Reading a module by parsing an in-memory LLVM IR string. - static std::unique_ptr from_bytes(std::string const & content, bool is_file); + static std::unique_ptr from_bytes(std::string const & content); // Construct from an externally created LLVM module explicit Module(UPModule&& module); From 6c14c1b65acf039833d6e17c32ac2c1147d71443 Mon Sep 17 00:00:00 2001 From: wongey <25296194+wongey@users.noreply.github.com> Date: Tue, 15 Jul 2025 14:54:43 -0400 Subject: [PATCH 09/18] Fix parse_ir_from_file test --- test/qiree/Module.test.cc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/test/qiree/Module.test.cc b/test/qiree/Module.test.cc index 2c682cd..9c7f8b5 100644 --- a/test/qiree/Module.test.cc +++ b/test/qiree/Module.test.cc @@ -110,7 +110,7 @@ TEST_F(ModuleTest, several_gates) } //---------------------------------------------------------------------------// -TEST(ModuleTest, parse_ir_from_file) { +TEST_F(ModuleTest, parse_ir_from_file) { // Helper function to read a file and return its contents as a string to be fed into from_bytes auto read_ll_file = [](const std::string& path) -> std::string { @@ -122,12 +122,11 @@ TEST(ModuleTest, parse_ir_from_file) { }; // Read the LLVM IR from a file and parse it - std::string ir = read_ll_file("bell.ll"); - // std::string_view ir_view(ir); + std::string ir = read_ll_file(this->test_data_path("bell.ll")); // Expect no exceptions during parsing EXPECT_NO_THROW({ - std::unique_ptr m = Module::from_bytes(ir, false); + std::unique_ptr m = Module::from_bytes(ir); }); } From 393aebc6d5f1af7e274a9f9edb84270f0355aabc Mon Sep 17 00:00:00 2001 From: wongey <25296194+wongey@users.noreply.github.com> Date: Wed, 16 Jul 2025 14:40:27 -0400 Subject: [PATCH 10/18] Remove local ignore from .gitignore --- .gitignore | 3 --- 1 file changed, 3 deletions(-) diff --git a/.gitignore b/.gitignore index 6bb6a10..0c4f53c 100644 --- a/.gitignore +++ b/.gitignore @@ -50,6 +50,3 @@ cmake_install.cmake /CMakeFiles .venv/ *.sif -examples/others/qcut_circuit* -examples/others/pyqir_wamta_example.py -scripts/apptainers/qiree.sif \ No newline at end of file From 95c86f2622c32093f1bba4e3c5fe19f918d6d5c1 Mon Sep 17 00:00:00 2001 From: wongey <25296194+wongey@users.noreply.github.com> Date: Thu, 17 Jul 2025 09:43:40 -0400 Subject: [PATCH 11/18] Remove cqiree files which belong to PR30 load_module changes will be pushed there once this branch is merged --- src/cqiree/QireeManager.cc | 246 ------------------------------------- 1 file changed, 246 deletions(-) delete mode 100644 src/cqiree/QireeManager.cc diff --git a/src/cqiree/QireeManager.cc b/src/cqiree/QireeManager.cc deleted file mode 100644 index 96bd2b8..0000000 --- a/src/cqiree/QireeManager.cc +++ /dev/null @@ -1,246 +0,0 @@ -//----------------------------------*-C++-*----------------------------------// -// Copyright 2025 UT-Battelle, LLC, and other QIR-EE developers. -// See the top-level COPYRIGHT file for details. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -//---------------------------------------------------------------------------// -//! \file cqiree/QireeManager.cc -//---------------------------------------------------------------------------// -#include "QireeManager.hh" - -#include -#include -#include - -#include "qiree_config.h" - -#include "qiree/Assert.hh" -#include "qiree/Executor.hh" -#include "qiree/Module.hh" -#include "qiree/QuantumInterface.hh" -#include "qiree/ResultDistribution.hh" -#include "qiree/SingleResultRuntime.hh" -#include "qirqsim/QsimQuantum.hh" -#include "qirqsim/QsimRuntime.hh" - -#define CQIREE_FAIL(CODE, MESSAGE) \ - do \ - { \ - std::cerr << "qiree failure: " << MESSAGE << '\n'; \ - return ReturnCode::CODE; \ - } while (0) - -namespace qiree -{ -//---------------------------------------------------------------------------// -QireeManager::QireeManager() = default; -QireeManager::~QireeManager() = default; - -//---------------------------------------------------------------------------// -QireeManager::ReturnCode -QireeManager::load_module(std::string_view data_contents) throw() -{ - try - { - // Load module from memory contents - std::string content{data_contents}; - // Convert string_view to string for Module constructor - module_ = Module::from_bytes(content); - } - catch (std::exception const& e) - { - CQIREE_FAIL(fail_load, e.what()); - } - return ReturnCode::success; -} - -//---------------------------------------------------------------------------// -QireeManager::ReturnCode QireeManager::load_module(std::string filename) throw() -{ - try - { - module_ = std::make_unique(filename); - QIREE_ENSURE(*module_); - } - catch (std::exception const& e) - { - std::cerr << "qiree failure: " << e.what() << '\n'; - CQIREE_FAIL(fail_load, e.what()); - } - - return ReturnCode::success; -} - -//---------------------------------------------------------------------------// -QireeManager::ReturnCode QireeManager::num_quantum_reg(int& result) const - throw() -{ - if (!module_) - { - CQIREE_FAIL(not_ready, "cannot query module before module load"); - } - if (execute_) - { - CQIREE_FAIL(not_ready, "cannot query module after creating executor"); - } - - auto attrs = module_->load_entry_point_attrs(); - result = attrs.required_num_qubits; - return ReturnCode::success; -} - -//---------------------------------------------------------------------------// -QireeManager::ReturnCode QireeManager::num_classical_reg(int& result) const - throw() -{ - if (!module_) - { - CQIREE_FAIL(not_ready, "cannot query module before module load"); - } - if (execute_) - { - CQIREE_FAIL(not_ready, "cannot query module after creating executor"); - } - - auto attrs = module_->load_entry_point_attrs(); - result = attrs.required_num_results; - return ReturnCode::success; -} - -//---------------------------------------------------------------------------// -QireeManager::ReturnCode -QireeManager::setup_executor(std::string_view backend, - std::string_view config_json) throw() -{ - if (!module_) - { - CQIREE_FAIL(not_ready, "cannot create executor before module load"); - } - if (execute_) - { - CQIREE_FAIL(not_ready, "cannot create executor again"); - } - - try - { - if (!config_json.empty()) - { - QIREE_NOT_IMPLEMENTED("CQiree JSON configuration input"); - } - - if (backend == "qsim") - { -#if QIREE_USE_QSIM - // Create runtime interface: give runtime a pointer to quantum - // (lifetime of the reference is guaranteed by our shared pointer - // copy) - constexpr unsigned long int seed = 0; - auto quantum = std::make_shared(std::cout, seed); - runtime_ = std::make_shared(std::cout, *quantum); - quantum_ = std::move(quantum); -#else - QIREE_NOT_CONFIGURED("QSim"); -#endif - } - else if (backend == "xacc") - { -#if QIREE_USE_XACC - QIREE_NOT_IMPLEMENTED("XACC backend for CQiree"); -#else - QIREE_NOT_CONFIGURED("XACC"); -#endif - } - else - { - QIREE_VALIDATE(false, - << "unknown backend name '" << backend << "'"); - } - } - catch (std::exception const& e) - { - CQIREE_FAIL(fail_load, - "error while creating quantum runtimes: " << e.what()); - } - - try - { - // Create executor with the module, quantum and runtime interfaces - QIREE_ASSERT(module_ && *module_); - execute_ = std::make_unique(std::move(*module_)); - } - catch (std::exception const& e) - { - CQIREE_FAIL(fail_load, "error while creating executor: " << e.what()); - } - - return ReturnCode::success; -} - -//---------------------------------------------------------------------------// -QireeManager::ReturnCode QireeManager::execute(int num_shots) throw() -{ - if (execute_) - { - CQIREE_FAIL(not_ready, "cannot create executor again"); - } - - if (num_shots <= 0) - { - CQIREE_FAIL(invalid_input, "num_shots was nonpositive"); - } - - try - { - QIREE_ASSERT(runtime_ && quantum_); - result_ = std::make_unique(); - - for (auto i = 0; i < num_shots; ++i) - { - (*execute_)(*quantum_, *runtime_); - result_->accumulate(runtime_->result()); - } - } - catch (std::exception const& e) - { - CQIREE_FAIL(fail_execute, e.what()); - } - return ReturnCode::success; -} - -//---------------------------------------------------------------------------// -QireeManager::ReturnCode QireeManager::num_results(int& count) const throw() -{ - if (!result_) - { - CQIREE_FAIL(not_ready, "execute has not been called"); - } - - count = static_cast(result_->size()); - - return ReturnCode::success; -} - -//---------------------------------------------------------------------------// -QireeManager::ReturnCode -QireeManager::get_result(int index, std::string_view key, int* count) const - throw() -{ - if (!result_) - { - CQIREE_FAIL(not_ready, "execute has not been called"); - } - - try - { - (void)sizeof(key); - (void)sizeof(count); - QIREE_NOT_IMPLEMENTED("getting results"); - } - catch (std::exception const& e) - { - CQIREE_FAIL(fail_execute, - "could not retrieve index " << index << ": " << e.what()); - } - return ReturnCode::success; -} -//---------------------------------------------------------------------------// -} // namespace qiree From 26f9ecc6aa81ca00514a93a2c88bea31f41395cd Mon Sep 17 00:00:00 2001 From: wongey <25296194+wongey@users.noreply.github.com> Date: Thu, 17 Jul 2025 13:43:16 -0400 Subject: [PATCH 12/18] Improve GTest finding and error message --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 676abe7..a8b2ea6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -172,10 +172,10 @@ if(QIREE_BUILD_DOCS) endif() if(QIREE_BUILD_TESTS AND NOT GTest_FOUND) - find_package(GTest REQUIRED) + find_package(GTest) if(NOT GTest_FOUND) - message(SEND_ERROR - "Googletest (GTest) is required for testing but was not found. Please install from source. Optional: In the user environment, you can run `cmake -DCMAKE_INSTALL_PREFIX=../install -DBUILD_SHARED_LIBS=ON ..` in the googletest/build folder, which allows you to build without sudo. Then you can set `export CMAKE_PREFIX_PATH=$HOME/googletest/install so that QIR-EE can find the installation." + message(FATAL_ERROR + "Googletest (GTest) is required for testing but was not found. Please install from source. Optional: If you are in a user environment, you can run `cmake -DCMAKE_INSTALL_PREFIX=../install -DBUILD_SHARED_LIBS=ON ..` in the googletest/build folder, which allows you to build without sudo. Then you can set `export CMAKE_PREFIX_PATH=$HOME/googletest/install so that QIR-EE can find the installation." ) endif() endif() From 760d98e44caf7eae168b5cd0aec26529c36ba77d Mon Sep 17 00:00:00 2001 From: wongey <25296194+wongey@users.noreply.github.com> Date: Thu, 17 Jul 2025 13:48:30 -0400 Subject: [PATCH 13/18] IWYU --- test/Test.hh | 3 --- test/qiree/Module.test.cc | 4 ++++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/test/Test.hh b/test/Test.hh index 82d064c..e5d3764 100644 --- a/test/Test.hh +++ b/test/Test.hh @@ -11,9 +11,6 @@ #include #include -#include -#include -#include namespace qiree { diff --git a/test/qiree/Module.test.cc b/test/qiree/Module.test.cc index 9c7f8b5..274285c 100644 --- a/test/qiree/Module.test.cc +++ b/test/qiree/Module.test.cc @@ -9,6 +9,10 @@ #include "qiree_test.hh" +#include +#include +#include + namespace qiree { namespace test From 06cb04d736fe81b04726cd85c2d7f8e3997d0d66 Mon Sep 17 00:00:00 2001 From: wongey <25296194+wongey@users.noreply.github.com> Date: Thu, 17 Jul 2025 15:56:12 -0400 Subject: [PATCH 14/18] Modify test so that it doesn't return a nullptr (per sethrj's wise suggestion) --- test/qiree/Module.test.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/qiree/Module.test.cc b/test/qiree/Module.test.cc index 274285c..641bce2 100644 --- a/test/qiree/Module.test.cc +++ b/test/qiree/Module.test.cc @@ -128,10 +128,10 @@ TEST_F(ModuleTest, parse_ir_from_file) { // Read the LLVM IR from a file and parse it std::string ir = read_ll_file(this->test_data_path("bell.ll")); + std::unique_ptr m; // Expect no exceptions during parsing - EXPECT_NO_THROW({ - std::unique_ptr m = Module::from_bytes(ir); - }); + EXPECT_NO_THROW(m = Module::from_bytes(ir)); + ASSERT_TRUE(m); } //---------------------------------------------------------------------------// From 22dd8b88e78419dc1225930e3bcea58d28659af0 Mon Sep 17 00:00:00 2001 From: wongey <25296194+wongey@users.noreply.github.com> Date: Thu, 17 Jul 2025 16:54:28 -0400 Subject: [PATCH 15/18] Add a QIR flag checker --- test/qiree/Module.test.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/qiree/Module.test.cc b/test/qiree/Module.test.cc index 641bce2..bdc8619 100644 --- a/test/qiree/Module.test.cc +++ b/test/qiree/Module.test.cc @@ -132,6 +132,10 @@ TEST_F(ModuleTest, parse_ir_from_file) { // Expect no exceptions during parsing EXPECT_NO_THROW(m = Module::from_bytes(ir)); ASSERT_TRUE(m); + + // Check flags + ASSERT_NE(ir.find("!llvm.module.flags"), std::string::npos) + << "QIR should contain a !llvm.module.flags metadata node"; } //---------------------------------------------------------------------------// From 5b122f68749e2990405aee9d04c37ad42185e614 Mon Sep 17 00:00:00 2001 From: wongey <25296194+wongey@users.noreply.github.com> Date: Thu, 17 Jul 2025 16:56:38 -0400 Subject: [PATCH 16/18] Format Module.cc with clang-format --- src/qiree/Module.cc | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/src/qiree/Module.cc b/src/qiree/Module.cc index 3456999..bae0fb4 100644 --- a/src/qiree/Module.cc +++ b/src/qiree/Module.cc @@ -7,16 +7,16 @@ //---------------------------------------------------------------------------// #include "Module.hh" +#include #include #include -#include #include #include #include #include #include -#include #include +#include #include "Assert.hh" @@ -166,24 +166,27 @@ Module::~Module() = default; Module::Module(Module&&) = default; Module& Module::operator=(Module&&) = default; -std::unique_ptr Module::from_bytes(std::string const & content) { - llvm::SMDiagnostic err; - - // Create memory buffer from the in-memory IR content - std::unique_ptr buffer = llvm::MemoryBuffer::getMemBuffer(content, "", false); +std::unique_ptr Module::from_bytes(std::string const& content) +{ + llvm::SMDiagnostic err; + + // Create memory buffer from the in-memory IR content + std::unique_ptr buffer + = llvm::MemoryBuffer::getMemBuffer(content, "", false); - // Parse the IR using LLVM context - auto llvm_module = llvm::parseIR(buffer->getMemBufferRef(), err, context()); + // Parse the IR using LLVM context + auto llvm_module = llvm::parseIR(buffer->getMemBufferRef(), err, context()); - if (!llvm_module) - { - err.print("qiree", llvm::errs()); - QIREE_VALIDATE(llvm_module, - << "Failed to parse QIR from in-memory content '" << content << "'"); - } + if (!llvm_module) + { + err.print("qiree", llvm::errs()); + QIREE_VALIDATE(llvm_module, + << "Failed to parse QIR from in-memory content '" + << content << "'"); + } - // Construct and return Module from parsed llvm::Module - return std::make_unique(std::move(llvm_module)); + // Construct and return Module from parsed llvm::Module + return std::make_unique(std::move(llvm_module)); } //---------------------------------------------------------------------------// From ac09e20c9a594ac26db5ca9075151bcea1ae94b7 Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Thu, 17 Jul 2025 17:04:21 -0400 Subject: [PATCH 17/18] iwyu --- src/qiree/Module.hh | 2 +- test/Test.hh | 2 -- test/qiree/Module.test.cc | 7 ++++--- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/qiree/Module.hh b/src/qiree/Module.hh index 11d266a..9c1ec05 100644 --- a/src/qiree/Module.hh +++ b/src/qiree/Module.hh @@ -8,7 +8,7 @@ #pragma once #include -#include +#include #include "Types.hh" diff --git a/test/Test.hh b/test/Test.hh index e5d3764..5847f7c 100644 --- a/test/Test.hh +++ b/test/Test.hh @@ -10,8 +10,6 @@ #include #include -#include - namespace qiree { namespace test diff --git a/test/qiree/Module.test.cc b/test/qiree/Module.test.cc index bdc8619..edb93f9 100644 --- a/test/qiree/Module.test.cc +++ b/test/qiree/Module.test.cc @@ -7,11 +7,12 @@ //---------------------------------------------------------------------------// #include "qiree/Module.hh" -#include "qiree_test.hh" - +#include #include -#include #include +#include + +#include "qiree_test.hh" namespace qiree { From c19911f4b99726ea03220f1f9388d4b1a6ccc4ec Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Thu, 17 Jul 2025 17:07:12 -0400 Subject: [PATCH 18/18] Fix constructor ordering --- src/qiree/Module.cc | 17 ++++++++++------- src/qiree/Module.hh | 24 ++++++++++++++---------- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/src/qiree/Module.cc b/src/qiree/Module.cc index bae0fb4..3c4775c 100644 --- a/src/qiree/Module.cc +++ b/src/qiree/Module.cc @@ -118,6 +118,7 @@ Module::Module(UPModule&& module) : module_{std::move(module)} //---------------------------------------------------------------------------// /*! * Construct with an LLVM module and an entry point. + * * Useful when there are multiple entry points. */ Module::Module(UPModule&& module, std::string const& entrypoint) @@ -158,14 +159,8 @@ Module::Module(std::string const& filename, std::string const& entrypoint) //---------------------------------------------------------------------------// /*! - * Reading a module by parsing an in-memory LLVM IR string. + * Read a module by parsing an in-memory LLVM IR string. */ - -Module::Module() = default; -Module::~Module() = default; -Module::Module(Module&&) = default; -Module& Module::operator=(Module&&) = default; - std::unique_ptr Module::from_bytes(std::string const& content) { llvm::SMDiagnostic err; @@ -189,6 +184,14 @@ std::unique_ptr Module::from_bytes(std::string const& content) return std::make_unique(std::move(llvm_module)); } +//! Construct in an empty state +Module::Module() = default; + +// Default destructor and move +Module::~Module() = default; +Module::Module(Module&&) = default; +Module& Module::operator=(Module&&) = default; + //---------------------------------------------------------------------------// /*! * Process entry point attributes. diff --git a/src/qiree/Module.hh b/src/qiree/Module.hh index 9c1ec05..8ce38c6 100644 --- a/src/qiree/Module.hh +++ b/src/qiree/Module.hh @@ -33,16 +33,6 @@ class Module //!@} public: - // Default empty constructor - Module(); - // Externally defined defaults - ~Module(); - Module(Module&&); - Module& operator=(Module&&); - // Prevent copying - Module(Module const&) = delete; - Module& operator=(Module const&) = delete; - // Reading a module by parsing an in-memory LLVM IR string. static std::unique_ptr from_bytes(std::string const & content); @@ -58,6 +48,20 @@ class Module // Construct with an LLVM IR file (bitcode or disassembled) and entry point Module(std::string const& filename, std::string const& entrypoint); + // Construct in an empty state + Module(); + + // Externally defined defaults + ~Module(); + Module(Module&&); + Module& operator=(Module&&); + + // Prevent copying + Module(Module const&) = delete; + Module& operator=(Module const&) = delete; + + //// ACCESSORS //// + // Process entry point attributes EntryPointAttrs load_entry_point_attrs() const;