blob: a68f0d518e9abab70a82d0a7766700b1774655b1 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#ifndef GANDIVA_LLVMGENERATOR_H
#define GANDIVA_LLVMGENERATOR_H
#include <cstdint>
#include <memory>
#include <string>
#include <vector>
#include "arrow/util/macros.h"
#include "gandiva/annotator.h"
#include "gandiva/compiled_expr.h"
#include "gandiva/configuration.h"
#include "gandiva/dex_visitor.h"
#include "gandiva/engine.h"
#include "gandiva/execution_context.h"
#include "gandiva/function_registry.h"
#include "gandiva/gandiva_aliases.h"
#include "gandiva/llvm_types.h"
#include "gandiva/lvalue.h"
#include "gandiva/selection_vector.h"
#include "gandiva/value_validity_pair.h"
#include "gandiva/visibility.h"
namespace gandiva {
class FunctionHolder;
/// Builds an LLVM module and generates code for the specified set of expressions.
class GANDIVA_EXPORT LLVMGenerator {
public:
/// \brief Factory method to initialize the generator.
static Status Make(std::shared_ptr<Configuration> config,
std::unique_ptr<LLVMGenerator>* llvm_generator);
/// \brief Build the code for the expression trees for default mode. Each
/// element in the vector represents an expression tree
Status Build(const ExpressionVector& exprs, SelectionVector::Mode mode);
/// \brief Build the code for the expression trees for default mode. Each
/// element in the vector represents an expression tree
Status Build(const ExpressionVector& exprs) {
return Build(exprs, SelectionVector::Mode::MODE_NONE);
}
/// \brief Execute the built expression against the provided arguments for
/// default mode.
Status Execute(const arrow::RecordBatch& record_batch,
const ArrayDataVector& output_vector);
/// \brief Execute the built expression against the provided arguments for
/// all modes. Only works on the records specified in the selection_vector.
Status Execute(const arrow::RecordBatch& record_batch,
const SelectionVector* selection_vector,
const ArrayDataVector& output_vector);
SelectionVector::Mode selection_vector_mode() { return selection_vector_mode_; }
LLVMTypes* types() { return engine_->types(); }
llvm::Module* module() { return engine_->module(); }
private:
LLVMGenerator();
FRIEND_TEST(TestLLVMGenerator, VerifyPCFunctions);
FRIEND_TEST(TestLLVMGenerator, TestAdd);
FRIEND_TEST(TestLLVMGenerator, TestNullInternal);
llvm::LLVMContext* context() { return engine_->context(); }
llvm::IRBuilder<>* ir_builder() { return engine_->ir_builder(); }
/// Visitor to generate the code for a decomposed expression.
class Visitor : public DexVisitor {
public:
Visitor(LLVMGenerator* generator, llvm::Function* function,
llvm::BasicBlock* entry_block, llvm::Value* arg_addrs,
llvm::Value* arg_local_bitmaps, llvm::Value* arg_context_ptr,
llvm::Value* loop_var);
void Visit(const VectorReadValidityDex& dex) override;
void Visit(const VectorReadFixedLenValueDex& dex) override;
void Visit(const VectorReadVarLenValueDex& dex) override;
void Visit(const LocalBitMapValidityDex& dex) override;
void Visit(const TrueDex& dex) override;
void Visit(const FalseDex& dex) override;
void Visit(const LiteralDex& dex) override;
void Visit(const NonNullableFuncDex& dex) override;
void Visit(const NullableNeverFuncDex& dex) override;
void Visit(const NullableInternalFuncDex& dex) override;
void Visit(const IfDex& dex) override;
void Visit(const BooleanAndDex& dex) override;
void Visit(const BooleanOrDex& dex) override;
void Visit(const InExprDexBase<int32_t>& dex) override;
void Visit(const InExprDexBase<int64_t>& dex) override;
void Visit(const InExprDexBase<std::string>& dex) override;
template <typename Type>
void VisitInExpression(const InExprDexBase<Type>& dex);
LValuePtr result() { return result_; }
bool has_arena_allocs() { return has_arena_allocs_; }
private:
enum BufferType { kBufferTypeValidity = 0, kBufferTypeData, kBufferTypeOffsets };
llvm::IRBuilder<>* ir_builder() { return generator_->ir_builder(); }
llvm::Module* module() { return generator_->module(); }
// Generate the code to build the combined validity (bitwise and) from the
// vector of validities.
llvm::Value* BuildCombinedValidity(const DexVector& validities);
// Generate the code to build the validity and the value for the given pair.
LValuePtr BuildValueAndValidity(const ValueValidityPair& pair);
// Generate code to build the params.
std::vector<llvm::Value*> BuildParams(FunctionHolder* holder,
const ValueValidityPairVector& args,
bool with_validity, bool with_context);
// Generate code to onvoke a function call.
LValuePtr BuildFunctionCall(const NativeFunction* func, DataTypePtr arrow_return_type,
std::vector<llvm::Value*>* params);
// Generate code for an if-else condition.
LValuePtr BuildIfElse(llvm::Value* condition, std::function<LValuePtr()> then_func,
std::function<LValuePtr()> else_func,
DataTypePtr arrow_return_type);
// Switch to the entry_block and get reference of the validity/value/offsets buffer
llvm::Value* GetBufferReference(int idx, BufferType buffer_type, FieldPtr field);
// Switch to the entry_block and get reference to the local bitmap.
llvm::Value* GetLocalBitMapReference(int idx);
// Clear the bit in the local bitmap, if is_valid is 'false'
void ClearLocalBitMapIfNotValid(int local_bitmap_idx, llvm::Value* is_valid);
LLVMGenerator* generator_;
LValuePtr result_;
llvm::Function* function_;
llvm::BasicBlock* entry_block_;
llvm::Value* arg_addrs_;
llvm::Value* arg_local_bitmaps_;
llvm::Value* arg_context_ptr_;
llvm::Value* loop_var_;
bool has_arena_allocs_;
};
// 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);
/// Generate code to load the vector at specified index in the 'arg_addrs' array.
llvm::Value* LoadVectorAtIndex(llvm::Value* arg_addrs, int idx,
const std::string& name);
/// Generate code to load the vector at specified index and cast it as bitmap.
llvm::Value* GetValidityReference(llvm::Value* arg_addrs, int idx, FieldPtr field);
/// Generate code to load the vector at specified index and cast it as data array.
llvm::Value* GetDataReference(llvm::Value* arg_addrs, int idx, FieldPtr field);
/// Generate code to load the vector at specified index and cast it as offsets array.
llvm::Value* GetOffsetsReference(llvm::Value* arg_addrs, int idx, FieldPtr field);
/// Generate code for the value array of one expression.
Status CodeGenExprValue(DexPtr value_expr, FieldDescriptorPtr output, int suffix_idx,
llvm::Function** fn,
SelectionVector::Mode selection_vector_mode);
/// Generate code to load the local bitmap specified index and cast it as bitmap.
llvm::Value* GetLocalBitMapReference(llvm::Value* arg_bitmaps, int idx);
/// Generate code to get the bit value at 'position' in the bitmap.
llvm::Value* GetPackedBitValue(llvm::Value* bitmap, llvm::Value* position);
/// Generate code to get the bit value at 'position' in the validity bitmap.
llvm::Value* GetPackedValidityBitValue(llvm::Value* bitmap, llvm::Value* position);
/// Generate code to set the bit value at 'position' in the bitmap to 'value'.
void SetPackedBitValue(llvm::Value* bitmap, llvm::Value* position, llvm::Value* value);
/// Generate code to clear the bit value at 'position' in the bitmap if 'value'
/// is false.
void ClearPackedBitValueIfFalse(llvm::Value* bitmap, llvm::Value* position,
llvm::Value* value);
// Generate code to build a DecimalLValue with specified value/precision/scale.
std::shared_ptr<DecimalLValue> BuildDecimalLValue(llvm::Value* value,
DataTypePtr arrow_type);
/// Generate code to make a function call (to a pre-compiled IR function) which takes
/// 'args' and has a return type 'ret_type'.
llvm::Value* AddFunctionCall(const std::string& full_name, llvm::Type* ret_type,
const std::vector<llvm::Value*>& args);
/// Compute the result bitmap for the expression.
///
/// \param[in] compiled_expr the compiled expression (includes the bitmap indices to be
/// used for computing the validity bitmap of the result).
/// \param[in] eval_batch (includes input/output buffer addresses)
/// \param[in] selection_vector the list of selected positions
void ComputeBitMapsForExpr(const CompiledExpr& compiled_expr,
const EvalBatch& eval_batch,
const SelectionVector* selection_vector);
/// Replace the %T in the trace msg with the correct type corresponding to 'type'
/// eg. %d for int32, %ld for int64, ..
std::string ReplaceFormatInTrace(const std::string& msg, llvm::Value* value,
std::string* print_fn);
/// Generate the code to print a trace msg with one optional argument (%T)
void AddTrace(const std::string& msg, llvm::Value* value = NULLPTR);
std::unique_ptr<Engine> engine_;
std::vector<std::unique_ptr<CompiledExpr>> compiled_exprs_;
FunctionRegistry function_registry_;
Annotator annotator_;
SelectionVector::Mode selection_vector_mode_;
// used for debug
bool dump_ir_;
bool optimise_ir_;
bool enable_ir_traces_;
std::vector<std::string> trace_strings_;
};
} // namespace gandiva
#endif // GANDIVA_LLVMGENERATOR_H