Skip to content

Commit

Permalink
New approach for preventing the optimisation of the vector variants.
Browse files Browse the repository at this point in the history
  • Loading branch information
bluescarni committed Aug 4, 2024
1 parent 9e37b0a commit 31779cd
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 33 deletions.
99 changes: 72 additions & 27 deletions src/detail/llvm_helpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include <boost/algorithm/string/predicate.hpp>
#include <boost/core/demangle.hpp>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/safe_numerics/safe_integer.hpp>

#include <fmt/format.h>
#include <fmt/ranges.h>
Expand Down Expand Up @@ -271,6 +272,74 @@ llvm::AttributeList llvm_ext_math_func_attrs(llvm_state &s)
return f->getAttributes();
}

// Add a pointer to the llvm.used global variable of a module:
//
// https://llvm.org/docs/LangRef.html#the-llvm-used-global-variable
//
// If the llvm.used variable does not exist yet, create it.
//
// NOTE: this has quadratic complexity. It should not be a problem
// for the type of use we do as we expect just a few entries in this
// array, but something to keep in mind.
void llvm_append_used(llvm_state &s, llvm::Constant *ptr)
{
assert(ptr != nullptr);
assert(ptr->getType()->isPointerTy());

auto &md = s.module();
auto &ctx = s.context();

// Fetch the pointer type.
auto *ptr_type = llvm::PointerType::getUnqual(ctx);

if (auto *orig_used = md.getGlobalVariable("llvm.used")) {
// The llvm.used variable exists already.

// Fetch the original initializer.
assert(orig_used->hasInitializer());
auto *orig_init = llvm::cast<llvm::ConstantArray>(orig_used->getInitializer());

// Construct a new initializer with the original values
// plus the new pointer.
std::vector<llvm::Constant *> arr_values;
arr_values.reserve(
boost::safe_numerics::safe<decltype(arr_values.size())>(orig_init->getType()->getNumElements()) + 1);
for (decltype(orig_init->getType()->getNumElements()) i = 0; i < orig_init->getType()->getNumElements(); ++i) {
auto *orig_el = orig_init->getAggregateElement(boost::numeric_cast<unsigned>(i));
assert(orig_el->getType()->isPointerTy());

// NOTE: if ptr was already in the llvm.used vector, just bail
// out early.
if (orig_el->isElementWiseEqual(ptr)) {
return;
}

arr_values.push_back(orig_el);
}
arr_values.push_back(ptr);

// Create the new array.
auto *used_array_type = llvm::ArrayType::get(ptr_type, boost::numeric_cast<std::uint64_t>(arr_values.size()));
auto *used_arr = llvm::ConstantArray::get(used_array_type, arr_values);

// Remove the original one.
orig_used->eraseFromParent();

// Add the new global variable.
auto *g_used_arr = new llvm::GlobalVariable(md, used_arr->getType(), true,
llvm::GlobalVariable::AppendingLinkage, used_arr, "llvm.used");
g_used_arr->setSection("llvm.metadata");
} else {
// The llvm.used variable does not exist yet, create it.
auto *used_array_type = llvm::ArrayType::get(ptr_type, 1);
std::vector<llvm::Constant *> arr_values{ptr};
auto *used_arr = llvm::ConstantArray::get(used_array_type, arr_values);
auto *g_used_arr = new llvm::GlobalVariable(md, used_arr->getType(), true,
llvm::GlobalVariable::AppendingLinkage, used_arr, "llvm.used");
g_used_arr->setSection("llvm.metadata");
}
}

// Attach the vfabi attributes to "call", which must be a call to a function with scalar arguments.
// The necessary vfabi information is stored in vfi. The function returns "call".
// The attributes of the scalar function will be attached to the vector variants.
Expand Down Expand Up @@ -365,33 +434,9 @@ llvm::CallInst *llvm_add_vfabi_attrs(llvm_state &s, llvm::CallInst *call, const
assert(vf_ptr->getAttributes() == f->getAttributes());
}

// Create the name of the dummy function to ensure the variant is not optimised out.
//
// NOTE: another way of doing this involves the llvm.used global variable - need
// to learn about the metadata API apparently.
//
// https://llvm.org/docs/LangRef.html#the-llvm-used-global-variable
// https://godbolt.org/z/1neaG4bYj
const auto dummy_name = fmt::format("heyoka.dummy_vector_call.{}", el_name);

if (auto *dummy_ptr = md.getFunction(dummy_name); dummy_ptr == nullptr) {
// The dummy function has not been defined yet, do it.
auto *dummy = llvm_func_create(vec_ft, llvm::Function::ExternalLinkage, dummy_name, &md);

builder.SetInsertPoint(llvm::BasicBlock::Create(context, "entry", dummy));

// The dummy function just forwards its arguments to the variant.
std::vector<llvm::Value *> dummy_args;
for (auto *dummy_arg = dummy->args().begin(); dummy_arg != dummy->args().end(); ++dummy_arg) {
dummy_args.emplace_back(dummy_arg);
}

builder.CreateRet(builder.CreateCall(vf_ptr, dummy_args));
} else {
// The declaration of the dummy function is already there.
// Check that the signatures match.
assert(dummy_ptr->getFunctionType() == vec_ft);
}
// Ensure that the variant is not optimised out because it is not
// explicitly used in the code.
detail::llvm_append_used(s, vf_ptr);
}

// Restore the original insertion block.
Expand Down
4 changes: 2 additions & 2 deletions src/llvm_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2359,16 +2359,16 @@ void llvm_multi_state::compile()
{.opt_bc = m_impl->m_jit->m_bc_snapshots,
.opt_ir = m_impl->m_jit->m_ir_snapshots,
.obj = m_impl->m_jit->m_object_files});
// LCOV_EXCL_START
}
// LCOV_EXCL_START
} catch (...) {
// Reset to a def-cted state in case of error,
// as it looks like there's no way of recovering.
m_impl.reset();

throw;
// LCOV_EXCL_STOP
}
// LCOV_EXCL_STOP
}

std::uintptr_t llvm_multi_state::jit_lookup(const std::string &name)
Expand Down
4 changes: 0 additions & 4 deletions test/llvm_multi_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -530,8 +530,6 @@ TEST_CASE("memcache testing")
REQUIRE(outs[3] == -1);
}

#if 0

// Tests to check vectorisation via the vector-function-abi-variant machinery.
TEST_CASE("vfabi double")
{
Expand Down Expand Up @@ -592,5 +590,3 @@ TEST_CASE("vfabi double")
#endif
}
}

#endif

0 comments on commit 31779cd

Please sign in to comment.