Skip to content

Commit

Permalink
Tweaks, doc additions, coverage fixes.
Browse files Browse the repository at this point in the history
  • Loading branch information
bluescarni committed Aug 4, 2024
1 parent 2ed7172 commit 9e37b0a
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 10 deletions.
27 changes: 19 additions & 8 deletions src/llvm_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -532,11 +532,13 @@ class string_view_mem_buffer final : public llvm::MemoryBuffer
// https://llvm.org/doxygen/MemoryBuffer_8cpp_source.html
this->init(s.data(), s.data() + s.size(), true);
}
// LCOV_EXCL_START
llvm::MemoryBuffer::BufferKind getBufferKind() const final
{
// Hopefully std::string is not memory-mapped...
return llvm::MemoryBuffer::BufferKind::MemoryBuffer_Malloc;
}
// LCOV_EXCL_STOP
};

// Helper to add an object file to the jit, throwing in case of errors.
Expand Down Expand Up @@ -1866,8 +1868,12 @@ struct llvm_multi_state::impl {

llvm_multi_state::llvm_multi_state() = default;

llvm_multi_state::llvm_multi_state(std::vector<llvm_state> states)
llvm_multi_state::llvm_multi_state(std::vector<llvm_state> states_)
{
// Fetch a const ref, as we want to make extra sure we do not modify
// states_ until we move it to construct the impl.
const auto &states = states_;

// We need at least 1 state.
if (states.empty()) [[unlikely]] {
throw std::invalid_argument("At least 1 llvm_state object is needed to construct an llvm_multi_state");
Expand Down Expand Up @@ -1934,30 +1940,35 @@ llvm_multi_state::llvm_multi_state(std::vector<llvm_state> states)
c_model, force_avx512, slp_vectorize);

// Build and assign the implementation.
impl imp{.m_states = std::move(states), .m_jit = std::move(jit)};
impl imp{.m_states = std::move(states_), .m_jit = std::move(jit)};
m_impl = std::make_unique<impl>(std::move(imp));
}

llvm_multi_state::llvm_multi_state(const llvm_multi_state &other)
{
// NOTE: start off by creating a new jit and copying the states.
// This will work regardless of whether other is compiled or not.
// No need to do any validation on the states are they are coming
// from a llvm_multi_state and they have been checked already.
impl imp{.m_states = other.m_impl->m_states,
.m_jit = std::make_unique<detail::multi_jit>(other.m_impl->m_jit->m_n_modules, other.get_opt_level(),
other.get_code_model(), other.force_avx512(),
other.get_slp_vectorize())};
m_impl = std::make_unique<impl>(std::move(imp));

if (other.is_compiled()) {
// 'other' was compiled. Reset builder and module, copy over the snapshots
// and the object files, and add the files to the jit.
// 'other' was compiled.

// Reset builder and module.
m_impl->m_jit->m_module.reset();
m_impl->m_jit->m_builder.reset();

// Copy over the snapshots and the object files,
m_impl->m_jit->m_object_files = other.m_impl->m_jit->m_object_files;
m_impl->m_jit->m_ir_snapshots = other.m_impl->m_jit->m_ir_snapshots;
m_impl->m_jit->m_bc_snapshots = other.m_impl->m_jit->m_bc_snapshots;

// Add the files to the jit.
for (const auto &obj : m_impl->m_jit->m_object_files) {
detail::add_obj_to_lljit(*m_impl->m_jit->m_lljit, obj);
}
Expand Down Expand Up @@ -2046,11 +2057,11 @@ void llvm_multi_state::load(boost::archive::binary_iarchive &ar, unsigned)
}

// Debug checks.
assert(m_impl->m_jit->m_object_files.empty()
assert((m_impl->m_jit->m_object_files.empty() && !cmp)
|| m_impl->m_jit->m_object_files.size() == m_impl->m_jit->m_n_modules);
assert(m_impl->m_jit->m_ir_snapshots.empty()
assert((m_impl->m_jit->m_object_files.empty() && !cmp)
|| m_impl->m_jit->m_ir_snapshots.size() == m_impl->m_jit->m_n_modules);
assert(m_impl->m_jit->m_bc_snapshots.empty()
assert((m_impl->m_jit->m_object_files.empty() && !cmp)
|| m_impl->m_jit->m_bc_snapshots.size() == m_impl->m_jit->m_n_modules);

// LCOV_EXCL_START
Expand Down Expand Up @@ -2305,7 +2316,7 @@ void llvm_multi_state::compile()

// NOTE: here it is important that we replicate the logic happening
// in llvm_state::compile(): clear out module/builder, construct
// the object file.
// the object file. The snapshots can be left empty.
for (auto &s : m_impl->m_states) {
s.m_module.reset();
s.m_builder.reset();
Expand Down
69 changes: 67 additions & 2 deletions test/llvm_multi_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,19 +96,52 @@ TEST_CASE("basic")
REQUIRE(ms.get_slp_vectorize());
REQUIRE(ms.get_code_model() == code_model::large);
REQUIRE(ms.get_n_modules() == 5u);

REQUIRE(!ms.is_compiled());

ms.compile();

REQUIRE(ms.is_compiled());

REQUIRE(ms.get_opt_level() == 1u);
REQUIRE(ms.fast_math());
REQUIRE(ms.force_avx512());
REQUIRE(ms.get_slp_vectorize());
REQUIRE(ms.get_code_model() == code_model::large);
REQUIRE(ms.get_n_modules() == 5u);

REQUIRE_THROWS_MATCHES(
ms.compile(), std::invalid_argument,
Message("The function 'compile' can be invoked only if the llvm_multi_state has not been compiled yet"));
}

// Move construction/assignment.
{
llvm_state s{kw::opt_level = 1u, kw::fast_math = true, kw::force_avx512 = true, kw::slp_vectorize = true,
kw::code_model = code_model::large};

llvm_multi_state ms{{s, s, s, s}};

auto ms2 = std::move(ms);

REQUIRE(ms2.get_opt_level() == 1u);
REQUIRE(ms2.fast_math());
REQUIRE(ms2.force_avx512());
REQUIRE(ms2.get_slp_vectorize());
REQUIRE(ms2.get_code_model() == code_model::large);
REQUIRE(ms2.get_n_modules() == 5u);
REQUIRE(!ms2.is_compiled());

ms2.compile();

llvm_multi_state ms3;
ms3 = std::move(ms2);

REQUIRE(ms3.is_compiled());
REQUIRE(ms3.get_opt_level() == 1u);
REQUIRE(ms3.fast_math());
REQUIRE(ms3.force_avx512());
REQUIRE(ms3.get_slp_vectorize());
REQUIRE(ms3.get_code_model() == code_model::large);
REQUIRE(ms3.get_n_modules() == 5u);
}
}

Expand Down Expand Up @@ -210,6 +243,38 @@ TEST_CASE("copy semantics")
REQUIRE(outs[1] == 2. / 3.);
}

// Test also copy assignment.
llvm_multi_state ms_copy3;
ms_copy3 = ms_copy2;

REQUIRE(ms_copy3.get_bc() == ms.get_bc());
REQUIRE(ms_copy3.get_ir() == ms.get_ir());
REQUIRE(ms_copy3.get_object_code() == ms.get_object_code());
REQUIRE(ms_copy3.is_compiled() == ms.is_compiled());
REQUIRE(ms_copy3.fast_math() == ms.fast_math());
REQUIRE(ms_copy3.force_avx512() == ms.force_avx512());
REQUIRE(ms_copy3.get_opt_level() == ms.get_opt_level());
REQUIRE(ms_copy3.get_slp_vectorize() == ms.get_slp_vectorize());
REQUIRE(ms_copy3.get_code_model() == ms.get_code_model());
REQUIRE_NOTHROW(ms_copy3.jit_lookup("f1"));
REQUIRE_NOTHROW(ms_copy3.jit_lookup("f2"));

{
auto *cf1_ptr = reinterpret_cast<void (*)(double *, const double *, const double *, const double *)>(
ms_copy3.jit_lookup("f1"));
auto *cf2_ptr = reinterpret_cast<void (*)(double *, const double *, const double *, const double *)>(
ms_copy3.jit_lookup("f2"));

const double ins[] = {2., 3.};
double outs[2] = {};

cf1_ptr(outs, ins, nullptr, nullptr);
cf2_ptr(outs + 1, ins, nullptr, nullptr);

REQUIRE(outs[0] == 6);
REQUIRE(outs[1] == 2. / 3.);
}

// Restore the cache.
llvm_state::set_memcache_limit(100'000'000ull);
}
Expand Down

0 comments on commit 9e37b0a

Please sign in to comment.