From 3d48e8cec7715dbdf974157b01b63c482c4464a4 Mon Sep 17 00:00:00 2001 From: Yue Ni Date: Mon, 5 Feb 2024 13:26:49 +0800 Subject: [PATCH 1/9] Add literal projection test. --- cpp/src/gandiva/engine.cc | 1 + cpp/src/gandiva/tests/projector_test.cc | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/cpp/src/gandiva/engine.cc b/cpp/src/gandiva/engine.cc index bfce72cefc6..c37e6b273e3 100644 --- a/cpp/src/gandiva/engine.cc +++ b/cpp/src/gandiva/engine.cc @@ -562,6 +562,7 @@ void Engine::AddGlobalMappingForFunc(const std::string& name, llvm::Type* ret_ty } arrow::Status Engine::AddGlobalMappings() { + ARROW_LOG(INFO) << "Adding global mappings for exported functions"; ARROW_RETURN_NOT_OK(ExportedFuncsRegistry::AddMappings(this)); ExternalCFunctions c_funcs(function_registry_); return c_funcs.AddMappings(this); diff --git a/cpp/src/gandiva/tests/projector_test.cc b/cpp/src/gandiva/tests/projector_test.cc index 59eeb3d92f1..00f96e744d9 100644 --- a/cpp/src/gandiva/tests/projector_test.cc +++ b/cpp/src/gandiva/tests/projector_test.cc @@ -3683,4 +3683,26 @@ TEST_F(TestProjector, TestExtendedCFunctionThatNeedsContext) { EXPECT_ARROW_ARRAY_EQUALS(out, outs.at(0)); } +TEST_F(TestProjector, TestLiteralProjection) { + auto in_field = field("in", arrow::int64()); + auto schema = arrow::schema({in_field}); + auto out_field = field("out", arrow::int64()); + auto literal = + TreeExprBuilder::MakeExpression(TreeExprBuilder::MakeLiteral(1LL), out_field); + + for (int i = 0; i < 1000; i++) { + std::shared_ptr projector; + ARROW_EXPECT_OK(Projector::Make(schema, {literal}, TestConfiguration(), &projector)); + + int num_records = 4; + auto array = MakeArrowArrayInt64({1, 2, 3, 4}, {true, true, true, true}); + auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array}); + auto out = MakeArrowArrayInt64({1, 1, 1, 1}, {true, true, true, true}); + + arrow::ArrayVector outs; + ARROW_EXPECT_OK(projector->Evaluate(*in_batch, pool_, &outs)); + EXPECT_ARROW_ARRAY_EQUALS(out, outs.at(0)); + } +} + } // namespace gandiva From de081e3b0e6c51a6403277511ef7fec95d11f3df Mon Sep 17 00:00:00 2001 From: Yue Ni Date: Wed, 7 Feb 2024 14:50:53 +0800 Subject: [PATCH 2/9] Re-use mangle instead of re-creating it every time. --- cpp/src/gandiva/engine.cc | 19 ++++++++++--------- cpp/src/gandiva/engine.h | 2 ++ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/cpp/src/gandiva/engine.cc b/cpp/src/gandiva/engine.cc index c37e6b273e3..a0565d44254 100644 --- a/cpp/src/gandiva/engine.cc +++ b/cpp/src/gandiva/engine.cc @@ -156,10 +156,9 @@ std::string DumpModuleIR(const llvm::Module& module) { return ir; } -void AddAbsoluteSymbol(llvm::orc::LLJIT& lljit, const std::string& name, +void AddAbsoluteSymbol(llvm::orc::JITDylib& jit_dylib, + llvm::orc::MangleAndInterner& mangle, const std::string& name, void* function_ptr) { - llvm::orc::MangleAndInterner mangle(lljit.getExecutionSession(), lljit.getDataLayout()); - // https://github.com/llvm/llvm-project/commit/8b1771bd9f304be39d4dcbdcccedb6d3bcd18200#diff-77984a824d9182e5c67a481740f3bc5da78d5bd4cf6e1716a083ddb30a4a4931 // LLVM 17 introduced ExecutorSymbolDef and move most of ORC APIs to ExecutorAddr #if LLVM_VERSION_MAJOR >= 17 @@ -171,21 +170,21 @@ void AddAbsoluteSymbol(llvm::orc::LLJIT& lljit, const std::string& name, llvm::JITSymbolFlags::Exported); #endif - auto error = lljit.getMainJITDylib().define( - llvm::orc::absoluteSymbols({{mangle(name), symbol}})); + auto error = jit_dylib.define(llvm::orc::absoluteSymbols({{mangle(name), symbol}})); llvm::cantFail(std::move(error)); } // add current process symbol to dylib // LLVM >= 18 does this automatically -void AddProcessSymbol(llvm::orc::LLJIT& lljit) { +void AddProcessSymbol(llvm::orc::LLJIT& lljit, llvm::orc::MangleAndInterner& mangle) { lljit.getMainJITDylib().addGenerator( llvm::cantFail(llvm::orc::DynamicLibrarySearchGenerator::GetForCurrentProcess( lljit.getDataLayout().getGlobalPrefix()))); // the `atexit` symbol cannot be found for ASAN #ifdef ADDRESS_SANITIZER if (!lljit.lookup("atexit")) { - AddAbsoluteSymbol(lljit, "atexit", reinterpret_cast(atexit)); + AddAbsoluteSymbol(lljit.getMainJITDylib(), mangle, "atexit", + reinterpret_cast(atexit)); } #endif } @@ -237,7 +236,6 @@ Result> BuildJIT( ARROW_ASSIGN_OR_RAISE(auto jit, AsArrowResult(maybe_jit, "Could not create LLJIT instance: ")); - AddProcessSymbol(*jit); return jit; } @@ -290,6 +288,9 @@ Engine::Engine(const std::shared_ptr& conf, function_registry_(conf->function_registry()), target_machine_(std::move(target_machine)), conf_(conf) { + mangle_ = std::make_unique(lljit_->getExecutionSession(), + lljit_->getDataLayout()); + AddProcessSymbol(*lljit_, *mangle_); // LLVM 10 doesn't like the expr function name to be the same as the module name auto module_id = "gdv_module_" + std::to_string(reinterpret_cast(this)); module_ = std::make_unique(module_id, *context_); @@ -558,7 +559,7 @@ void Engine::AddGlobalMappingForFunc(const std::string& name, llvm::Type* ret_ty const std::vector& args, void* func) { auto const prototype = llvm::FunctionType::get(ret_type, args, /*is_var_arg*/ false); llvm::Function::Create(prototype, llvm::GlobalValue::ExternalLinkage, name, module()); - AddAbsoluteSymbol(*lljit_, name, func); + AddAbsoluteSymbol(lljit_->getMainJITDylib(), *mangle_, name, func); } arrow::Status Engine::AddGlobalMappings() { diff --git a/cpp/src/gandiva/engine.h b/cpp/src/gandiva/engine.h index 565c3f14250..daa13b3d83b 100644 --- a/cpp/src/gandiva/engine.h +++ b/cpp/src/gandiva/engine.h @@ -26,6 +26,7 @@ #include #include +#include #include "arrow/util/logging.h" #include "arrow/util/macros.h" @@ -115,6 +116,7 @@ class GANDIVA_EXPORT Engine { std::unique_ptr context_; std::unique_ptr lljit_; + std::unique_ptr mangle_; std::unique_ptr> ir_builder_; std::unique_ptr module_; LLVMTypes types_; From 787e215da37c55587af08b7d483e9a6869a9fbde Mon Sep 17 00:00:00 2001 From: Yue Ni Date: Wed, 7 Feb 2024 23:23:59 +0800 Subject: [PATCH 3/9] Avoid adding func mapping if it is not used in the expression for better performance. --- cpp/src/gandiva/engine.cc | 8 +++++--- cpp/src/gandiva/engine.h | 8 +++++--- cpp/src/gandiva/expr_decomposer.cc | 1 + cpp/src/gandiva/expr_decomposer.h | 6 ++++++ cpp/src/gandiva/llvm_generator.cc | 24 +++++++++++++++++++++--- cpp/src/gandiva/llvm_generator.h | 6 +++++- 6 files changed, 43 insertions(+), 10 deletions(-) diff --git a/cpp/src/gandiva/engine.cc b/cpp/src/gandiva/engine.cc index a0565d44254..fe5dd1025dd 100644 --- a/cpp/src/gandiva/engine.cc +++ b/cpp/src/gandiva/engine.cc @@ -298,7 +298,8 @@ Engine::Engine(const std::shared_ptr& conf, Engine::~Engine() {} -Status Engine::Init() { +Status Engine::Init(std::unordered_set function_names) { + used_functions_ = std::move(function_names); std::call_once(register_exported_funcs_flag, gandiva::RegisterExportedFuncs); // Add mappings for global functions that can be accessed from LLVM/IR module. @@ -331,7 +332,6 @@ Result> Engine::Make( std::unique_ptr engine{ new Engine(conf, std::move(jit), std::move(target_machine), cached)}; - ARROW_RETURN_NOT_OK(engine->Init()); return engine; } @@ -557,13 +557,15 @@ Result Engine::CompiledFunction(const std::string& function) { void Engine::AddGlobalMappingForFunc(const std::string& name, llvm::Type* ret_type, const std::vector& args, void* func) { + if (used_functions_.find(name) == used_functions_.end()) { + return; + } auto const prototype = llvm::FunctionType::get(ret_type, args, /*is_var_arg*/ false); llvm::Function::Create(prototype, llvm::GlobalValue::ExternalLinkage, name, module()); AddAbsoluteSymbol(lljit_->getMainJITDylib(), *mangle_, name, func); } arrow::Status Engine::AddGlobalMappings() { - ARROW_LOG(INFO) << "Adding global mappings for exported functions"; ARROW_RETURN_NOT_OK(ExportedFuncsRegistry::AddMappings(this)); ExternalCFunctions c_funcs(function_registry_); return c_funcs.AddMappings(this); diff --git a/cpp/src/gandiva/engine.h b/cpp/src/gandiva/engine.h index daa13b3d83b..5dc3ed9a8d8 100644 --- a/cpp/src/gandiva/engine.h +++ b/cpp/src/gandiva/engine.h @@ -91,14 +91,15 @@ class GANDIVA_EXPORT Engine { /// Load the function IRs that can be accessed in the module. Status LoadFunctionIRs(); + /// Post construction init. This _must_ be called after the constructor. + /// @param[in] used_functions set of function names that are expected to be used by the engine + Status Init(std::unordered_set used_functions); + private: Engine(const std::shared_ptr& conf, std::unique_ptr lljit, std::unique_ptr target_machine, bool cached); - // Post construction init. This _must_ be called after the constructor. - Status Init(); - static void InitOnce(); /// load pre-compiled IR modules from precompiled_bitcode.cc and merge them into @@ -122,6 +123,7 @@ class GANDIVA_EXPORT Engine { LLVMTypes types_; std::vector functions_to_compile_; + std::unordered_set used_functions_; bool optimize_ = true; bool module_finalized_ = false; diff --git a/cpp/src/gandiva/expr_decomposer.cc b/cpp/src/gandiva/expr_decomposer.cc index df8eed5fd63..9fdfe089735 100644 --- a/cpp/src/gandiva/expr_decomposer.cc +++ b/cpp/src/gandiva/expr_decomposer.cc @@ -69,6 +69,7 @@ Status ExprDecomposer::Visit(const FunctionNode& in_node) { const NativeFunction* native_function = registry_.LookupSignature(signature); DCHECK(native_function) << "Missing Signature " << signature.ToString(); + used_functions_.emplace(native_function->pc_name()); // decompose the children. std::vector args; for (auto& child : node.children()) { diff --git a/cpp/src/gandiva/expr_decomposer.h b/cpp/src/gandiva/expr_decomposer.h index 90a27744b36..e3de40d62b5 100644 --- a/cpp/src/gandiva/expr_decomposer.h +++ b/cpp/src/gandiva/expr_decomposer.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "gandiva/arrow.h" @@ -49,6 +50,10 @@ class GANDIVA_EXPORT ExprDecomposer : public NodeVisitor { return status; } + [[nodiscard]] const std::unordered_set& UsedFunctions() const { + return used_functions_; + } + private: ARROW_DISALLOW_COPY_AND_ASSIGN(ExprDecomposer); @@ -125,6 +130,7 @@ class GANDIVA_EXPORT ExprDecomposer : public NodeVisitor { Annotator& annotator_; std::stack> if_entries_stack_; ValueValidityPairPtr result_; + std::unordered_set used_functions_; bool nested_if_else_; }; diff --git a/cpp/src/gandiva/llvm_generator.cc b/cpp/src/gandiva/llvm_generator.cc index 62ebab08f4d..5f6993798bb 100644 --- a/cpp/src/gandiva/llvm_generator.cc +++ b/cpp/src/gandiva/llvm_generator.cc @@ -66,12 +66,20 @@ Status LLVMGenerator::SetLLVMObjectCache(GandivaObjectCache& object_cache) { return engine_->SetLLVMObjectCache(object_cache); } -Status LLVMGenerator::Add(const ExpressionPtr expr, const FieldDescriptorPtr output) { - int idx = static_cast(compiled_exprs_.size()); +arrow::Result LLVMGenerator::Decompose(const ExpressionPtr& expr) { // decompose the expression to separate out value and validities. ExprDecomposer decomposer(*function_registry_, annotator_); ValueValidityPairPtr value_validity; ARROW_RETURN_NOT_OK(decomposer.Decompose(*expr->root(), &value_validity)); + + auto& used_functions = decomposer.UsedFunctions(); + functions_in_exprs_.insert(used_functions.begin(), used_functions.end()); + return value_validity; +} + +Status LLVMGenerator::Add(const ExpressionPtr expr, ValueValidityPairPtr value_validity, + const FieldDescriptorPtr output) { + int idx = static_cast(compiled_exprs_.size()); // Generate the IR function for the decomposed expression. auto compiled_expr = std::make_unique(value_validity, output); std::string fn_name = "expr_" + std::to_string(idx) + "_" + @@ -92,9 +100,19 @@ Status LLVMGenerator::Add(const ExpressionPtr expr, const FieldDescriptorPtr out Status LLVMGenerator::Build(const ExpressionVector& exprs, SelectionVector::Mode mode) { selection_vector_mode_ = mode; + std::vector expr_value_validities; for (auto& expr : exprs) { + ARROW_ASSIGN_OR_RAISE(auto value_validity, Decompose(expr)); + expr_value_validities.push_back(value_validity); + } + + ARROW_RETURN_NOT_OK(engine_->Init(std::move(functions_in_exprs_))); + + for (size_t i = 0; i < exprs.size(); ++i) { + const auto& expr = exprs[i]; auto output = annotator_.AddOutputFieldDescriptor(expr->result()); - ARROW_RETURN_NOT_OK(Add(expr, output)); + auto value_validity = expr_value_validities[i]; + ARROW_RETURN_NOT_OK(Add(expr, std::move(value_validity), output)); } // Compile and inject into the process' memory the generated function. diff --git a/cpp/src/gandiva/llvm_generator.h b/cpp/src/gandiva/llvm_generator.h index 0c532998e8b..9fa5ad35742 100644 --- a/cpp/src/gandiva/llvm_generator.h +++ b/cpp/src/gandiva/llvm_generator.h @@ -184,9 +184,12 @@ class GANDIVA_EXPORT LLVMGenerator { bool has_arena_allocs_; }; + arrow::Result Decompose(const ExpressionPtr& expr); + // Generate the code for one expression for default mode, with the output of // the expression going to 'output'. - Status Add(const ExpressionPtr expr, const FieldDescriptorPtr output); + Status Add(const ExpressionPtr expr, ValueValidityPairPtr value_validity, + const FieldDescriptorPtr output); /// Generate code to load the vector at specified index in the 'arg_addrs' array. llvm::Value* LoadVectorAtIndex(llvm::Value* arg_addrs, llvm::Type* type, int idx, @@ -263,6 +266,7 @@ class GANDIVA_EXPORT LLVMGenerator { // used for debug bool enable_ir_traces_; std::vector trace_strings_; + std::unordered_set functions_in_exprs_; }; } // namespace gandiva From 10c85d28a68ed1263c0aa98552552cd3fdfaa6e7 Mon Sep 17 00:00:00 2001 From: Yue Ni Date: Wed, 7 Feb 2024 23:24:54 +0800 Subject: [PATCH 4/9] Avoid loading IR and linking IR into module if all functions are C functions. --- cpp/src/gandiva/engine.cc | 16 ++++++++++------ cpp/src/gandiva/engine.h | 12 +++++++++++- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/cpp/src/gandiva/engine.cc b/cpp/src/gandiva/engine.cc index fe5dd1025dd..8a533315587 100644 --- a/cpp/src/gandiva/engine.cc +++ b/cpp/src/gandiva/engine.cc @@ -308,7 +308,7 @@ Status Engine::Init(std::unordered_set function_names) { } Status Engine::LoadFunctionIRs() { - if (!functions_loaded_) { + if (!functions_loaded_ && used_functions_.size() > used_c_functions_.size()) { ARROW_RETURN_NOT_OK(LoadPreCompiledIR()); ARROW_RETURN_NOT_OK(DecimalIR::AddFunctions(this)); ARROW_RETURN_NOT_OK(LoadExternalPreCompiledIR()); @@ -557,12 +557,16 @@ Result Engine::CompiledFunction(const std::string& function) { void Engine::AddGlobalMappingForFunc(const std::string& name, llvm::Type* ret_type, const std::vector& args, void* func) { - if (used_functions_.find(name) == used_functions_.end()) { - return; + // if the function is not used, don't add it to the module for better performance + bool is_internal_func = internal_functions_.find(name) != internal_functions_.end(); + if (is_internal_func || used_functions_.find(name) != used_functions_.end()) { + if (!is_internal_func) { + used_c_functions_.emplace(name); + } + auto const prototype = llvm::FunctionType::get(ret_type, args, /*is_var_arg*/ false); + llvm::Function::Create(prototype, llvm::GlobalValue::ExternalLinkage, name, module()); + AddAbsoluteSymbol(lljit_->getMainJITDylib(), *mangle_, name, func); } - auto const prototype = llvm::FunctionType::get(ret_type, args, /*is_var_arg*/ false); - llvm::Function::Create(prototype, llvm::GlobalValue::ExternalLinkage, name, module()); - AddAbsoluteSymbol(lljit_->getMainJITDylib(), *mangle_, name, func); } arrow::Status Engine::AddGlobalMappings() { diff --git a/cpp/src/gandiva/engine.h b/cpp/src/gandiva/engine.h index 5dc3ed9a8d8..c5219349c7c 100644 --- a/cpp/src/gandiva/engine.h +++ b/cpp/src/gandiva/engine.h @@ -92,7 +92,8 @@ class GANDIVA_EXPORT Engine { Status LoadFunctionIRs(); /// Post construction init. This _must_ be called after the constructor. - /// @param[in] used_functions set of function names that are expected to be used by the engine + /// @param[in] used_functions set of function names that are expected to be used by the + /// engine Status Init(std::unordered_set used_functions); private: @@ -124,6 +125,15 @@ class GANDIVA_EXPORT Engine { std::vector functions_to_compile_; std::unordered_set used_functions_; + std::unordered_set used_c_functions_; + static inline const std::unordered_set internal_functions_ = { + "gdv_fn_populate_varlen_vector", + "gdv_fn_context_arena_reset", + "bitMapGetBit", + "bitMapValidityGetBit", + "bitMapClearBitIfFalse", + "gdv_fn_context_arena_malloc", + "gdv_fn_context_set_error_msg"}; bool optimize_ = true; bool module_finalized_ = false; From 200d0266db6fc6ea2b1d4aec040bd2721b1191a0 Mon Sep 17 00:00:00 2001 From: Yue Ni Date: Thu, 8 Feb 2024 14:29:00 +0800 Subject: [PATCH 5/9] Separate bitcode into two parts, one mandatory bitcode which will always be loaded, and other part is optional and will be loaded when necessary. --- cpp/src/gandiva/CMakeLists.txt | 1 + cpp/src/gandiva/engine.cc | 35 ++++++++++++++++----- cpp/src/gandiva/engine.h | 6 ++++ cpp/src/gandiva/make_precompiled_bitcode.py | 24 ++++++++------ cpp/src/gandiva/precompiled/CMakeLists.txt | 33 ++++++++++++------- cpp/src/gandiva/precompiled_bitcode.cc.in | 5 +++ 6 files changed, 74 insertions(+), 30 deletions(-) diff --git a/cpp/src/gandiva/CMakeLists.txt b/cpp/src/gandiva/CMakeLists.txt index d773fb5ff58..633bf07294c 100644 --- a/cpp/src/gandiva/CMakeLists.txt +++ b/cpp/src/gandiva/CMakeLists.txt @@ -36,6 +36,7 @@ provide_cmake_module(GandivaAddBitcode "Gandiva") # Set the path where the bitcode file generated, see precompiled/CMakeLists.txt set(GANDIVA_PRECOMPILED_BC_PATH "${CMAKE_CURRENT_BINARY_DIR}/irhelpers.bc") +set(GANDIVA_PRECOMPILED_MANDATORY_BC_PATH "${CMAKE_CURRENT_BINARY_DIR}/mandatory_ir.bc") set(GANDIVA_PRECOMPILED_CC_PATH "${CMAKE_CURRENT_BINARY_DIR}/precompiled_bitcode.cc") set(GANDIVA_PRECOMPILED_CC_IN_PATH "${CMAKE_CURRENT_SOURCE_DIR}/precompiled_bitcode.cc.in") diff --git a/cpp/src/gandiva/engine.cc b/cpp/src/gandiva/engine.cc index 8a533315587..520d29a2815 100644 --- a/cpp/src/gandiva/engine.cc +++ b/cpp/src/gandiva/engine.cc @@ -115,6 +115,9 @@ namespace gandiva { extern const unsigned char kPrecompiledBitcode[]; extern const size_t kPrecompiledBitcodeSize; +extern const unsigned char kPrecompiledMandatoryBitcode[]; +extern const size_t kPrecompiledMandatoryBitcodeSize; + std::once_flag llvm_init_once_flag; static bool llvm_init = false; static llvm::StringRef cpu_name; @@ -308,6 +311,11 @@ Status Engine::Init(std::unordered_set function_names) { } Status Engine::LoadFunctionIRs() { + if (!mandatory_functions_loaded_) { + ARROW_RETURN_NOT_OK(LoadMandatoryPreCompiledIR()); + mandatory_functions_loaded_ = true; + } + if (!functions_loaded_ && used_functions_.size() > used_c_functions_.size()) { ARROW_RETURN_NOT_OK(LoadPreCompiledIR()); ARROW_RETURN_NOT_OK(DecimalIR::AddFunctions(this)); @@ -361,14 +369,11 @@ llvm::Module* Engine::module() { return module_.get(); } -// Handling for pre-compiled IR libraries. -Status Engine::LoadPreCompiledIR() { - auto const bitcode = llvm::StringRef(reinterpret_cast(kPrecompiledBitcode), - kPrecompiledBitcodeSize); - +Status LoadIR(const std::string& name, llvm::StringRef bitcode, llvm::Module& module, + llvm::LLVMContext& context) { /// Read from file into memory buffer. llvm::ErrorOr> buffer_or_error = - llvm::MemoryBuffer::getMemBuffer(bitcode, "precompiled", false); + llvm::MemoryBuffer::getMemBuffer(bitcode, name, false); ARROW_RETURN_IF(!buffer_or_error, Status::CodeGenError("Could not load module from IR: ", @@ -378,13 +383,27 @@ Status Engine::LoadPreCompiledIR() { /// Parse the IR module. llvm::Expected> module_or_error = - llvm::getOwningLazyBitcodeModule(std::move(buffer), *context()); + llvm::getOwningLazyBitcodeModule(std::move(buffer), context); // NOTE: llvm::handleAllErrors() fails linking with RTTI-disabled LLVM builds // (ARROW-5148) - ARROW_RETURN_NOT_OK(VerifyAndLinkModule(*module_, std::move(module_or_error))); + ARROW_RETURN_NOT_OK(VerifyAndLinkModule(module, std::move(module_or_error))); return Status::OK(); } +// Handling for pre-compiled IR libraries. +Status Engine::LoadPreCompiledIR() { + auto const bitcode = llvm::StringRef(reinterpret_cast(kPrecompiledBitcode), + kPrecompiledBitcodeSize); + return LoadIR("precompiled", bitcode, *module_, *context()); +} + +Status Engine::LoadMandatoryPreCompiledIR() { + auto const bitcode = + llvm::StringRef(reinterpret_cast(kPrecompiledMandatoryBitcode), + kPrecompiledMandatoryBitcodeSize); + return LoadIR("mandatory_precompiled", bitcode, *module_, *context()); +} + static llvm::MemoryBufferRef AsLLVMMemoryBuffer(const arrow::Buffer& arrow_buffer) { auto const data = reinterpret_cast(arrow_buffer.data()); auto const size = arrow_buffer.size(); diff --git a/cpp/src/gandiva/engine.h b/cpp/src/gandiva/engine.h index c5219349c7c..4dd573bb5f8 100644 --- a/cpp/src/gandiva/engine.h +++ b/cpp/src/gandiva/engine.h @@ -107,6 +107,10 @@ class GANDIVA_EXPORT Engine { /// the main module. Status LoadPreCompiledIR(); + /// load mandatory pre-compiled IR modules from precompiled_bitcode.cc and merge them into + /// the main module. Mandatory IR includes functions manipulating bitmaps + Status LoadMandatoryPreCompiledIR(); + // load external pre-compiled bitcodes into module Status LoadExternalPreCompiledIR(); @@ -130,6 +134,7 @@ class GANDIVA_EXPORT Engine { "gdv_fn_populate_varlen_vector", "gdv_fn_context_arena_reset", "bitMapGetBit", + "bitMapSetBit", "bitMapValidityGetBit", "bitMapClearBitIfFalse", "gdv_fn_context_arena_malloc", @@ -139,6 +144,7 @@ class GANDIVA_EXPORT Engine { bool module_finalized_ = false; bool cached_; bool functions_loaded_ = false; + bool mandatory_functions_loaded_ = false; std::shared_ptr function_registry_; std::string module_ir_; std::unique_ptr target_machine_; diff --git a/cpp/src/gandiva/make_precompiled_bitcode.py b/cpp/src/gandiva/make_precompiled_bitcode.py index 97d96f8a878..c515748232a 100644 --- a/cpp/src/gandiva/make_precompiled_bitcode.py +++ b/cpp/src/gandiva/make_precompiled_bitcode.py @@ -19,7 +19,6 @@ import sys -marker = b"" def expand(data): """ @@ -29,21 +28,26 @@ def expand(data): return expanded_data.encode('ascii') -def apply_template(template, data): +def apply_template(template, marker, data): if template.count(marker) != 1: raise ValueError("Invalid template") return template.replace(marker, expand(data)) +def read_file(filepath): + with open(filepath, "rb") as file: + return file.read() if __name__ == "__main__": - if len(sys.argv) != 4: - raise ValueError("Usage: {0}