Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,5 @@ compile_commands.json
cmake_install.cmake
/CMakeCache.txt
/CMakeFiles
.venv/
*.sif
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,8 @@ 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(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()
Expand Down
32 changes: 32 additions & 0 deletions src/qiree/Module.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@
//---------------------------------------------------------------------------//
#include "Module.hh"

#include <memory>
#include <sstream>
#include <string_view>
#include <llvm/IR/Attributes.h>
#include <llvm/IR/Constants.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/Module.h>
#include <llvm/IRReader/IRReader.h>
#include <llvm/Support/MemoryBuffer.h>
#include <llvm/Support/SourceMgr.h>

#include "Assert.hh"
Expand Down Expand Up @@ -116,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)
Expand Down Expand Up @@ -155,7 +158,36 @@ Module::Module(std::string const& filename, std::string const& entrypoint)
}

//---------------------------------------------------------------------------//
/*!
* Read a module by parsing an in-memory LLVM IR string.
*/
std::unique_ptr<Module> Module::from_bytes(std::string const& content)
{
llvm::SMDiagnostic err;

// Create memory buffer from the in-memory IR content
std::unique_ptr<llvm::MemoryBuffer> buffer
= llvm::MemoryBuffer::getMemBuffer(content, "<in-memory>", 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 '"
<< content << "'");
}

// Construct and return Module from parsed llvm::Module
return std::make_unique<Module>(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;
Expand Down
26 changes: 17 additions & 9 deletions src/qiree/Module.hh
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#pragma once

#include <memory>
#include <string>

#include "Types.hh"

Expand All @@ -32,15 +33,8 @@ 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<Module> from_bytes(std::string const & content);

// Construct from an externally created LLVM module
explicit Module(UPModule&& module);
Expand All @@ -54,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;

Expand Down
30 changes: 30 additions & 0 deletions test/qiree/Module.test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
//---------------------------------------------------------------------------//
#include "qiree/Module.hh"

#include <fstream>
#include <sstream>
#include <stdexcept>
#include <string>

#include "qiree_test.hh"

namespace qiree
Expand Down Expand Up @@ -109,6 +114,31 @@ TEST_F(ModuleTest, several_gates)
EXPECT_FALSE(flags.dynamic_result_management);
}

//---------------------------------------------------------------------------//
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 {
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(this->test_data_path("bell.ll"));

std::unique_ptr<Module> m;
// 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";
}

//---------------------------------------------------------------------------//
} // namespace test
} // namespace qiree