blob: 0da79d0dc5cfeda02c2eac3284de55eb6be6ebb8 [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 IMPALA_EXPRS_SCALAR_EXPR_H
#define IMPALA_EXPRS_SCALAR_EXPR_H
#include <memory>
#include <string>
#include <vector>
#include <boost/scoped_ptr.hpp>
#include "common/global-types.h"
#include "common/status.h"
#include "exprs/expr.h"
#include "impala-ir/impala-ir-functions.h"
#include "runtime/types.h"
#include "udf/udf-internal.h" // for CollectionVal
#include "udf/udf.h"
namespace llvm {
class BasicBlock;
class Function;
class Type;
class Value;
};
namespace impala {
using impala_udf::FunctionContext;
using impala_udf::AnyVal;
using impala_udf::BooleanVal;
using impala_udf::TinyIntVal;
using impala_udf::SmallIntVal;
using impala_udf::IntVal;
using impala_udf::BigIntVal;
using impala_udf::FloatVal;
using impala_udf::DoubleVal;
using impala_udf::TimestampVal;
using impala_udf::StringVal;
using impala_udf::DecimalVal;
using impala_udf::DateVal;
using impala_udf::CollectionVal;
struct LibCacheEntry;
class LlvmCodeGen;
class MemTracker;
class ObjectPool;
class RowDescriptor;
class RuntimeState;
class ScalarExprEvaluator;
class SlotDescriptor;
class TColumnValue;
class TExpr;
class TExprNode;
class Tuple;
class TupleRow;
/// --- ScalarExpr overview
///
/// ScalarExpr is an expression which returns a value for each input tuple row.
/// Examples include built-in functions such as abs(), UDF, case-expr and literal
/// such as a string "foobar". It's a subclass of Expr which represents an expression
/// as a tree.
///
/// --- Implementation:
///
/// ScalarExpr implements compute function, which given a row, performs the computation
/// of an expr and produces scalar result. This function evaluates the necessary child
/// arguments by calling their compute functions, then performs whatever computation is
/// necessary on the arguments to generate the result. These compute functions have
/// signature Get*Val(ScalarExprEvaluator*, const TupleRow*). One is implemented for each
/// possible return type it supports (e.g. GetBooleanVal(), GetStringVal(), etc). The
/// return type is a subclass of AnyVal (e.g. StringVal). Get*Val() dispatches to either
/// a codegen'd function pointer or to an interpreted implementation Get*ValInterpreted()
/// These interpreted functions must be overridden by subclasses of ScalarExpr for every
/// type that they may return.
///
/// ScalarExpr contains query compile-time information about an expression (e.g.
/// sub-expressions implicitly encoded in the tree structure) and the LLVM IR compute
/// functions. ScalarExprEvaluator is the interface for evaluating a scalar expression
/// against an input TupleRow.
///
/// ScalarExpr's compute functions are codegend to replace calls to the generic compute
/// function of child expressions with the exact compute functions based on the return
/// types of the child expressions known at runtime. Subclasses should override
/// GetCodegendComputeFnImpl() to either generate custom IR compute functions using
/// IRBuilder, which inlines calls to child expressions' compute functions, or simply call
/// GetCodegendComputeFnWrapper() to generate a wrapper function to call the interpreted
/// compute function. Note that we do not need a separate GetCodegendComputeFn() for each
/// type.
///
/// The two main usage patterns for ScalarExpr are:
/// * The codegen'd expressions are called from other codegen'd functions, e.g. from a
/// codegen'd join implementation
/// * Get*Val() is called on the root of each expression subtree by interpreted code
/// (e.g. an operator which doesn't support codegen yet).
/// We can optimize for the second usage pattern by filling in the codegen'd function
/// pointer (codegend_compute_fn_) in root of each ScalarExpr tree. Individual callsites
/// can disable this optimisation if it's not needed. Expr subtrees can be evaluated
/// (e.g. by ScalarExprEvaluator::GetConstValue()) but may fail back to a slower
/// interpreted implementation.
///
/// TODO: remove GetCodegendComputeFnWrapper(), which is a hack to enable "codegen"
/// by generating LLVM functions that actually call into the interpreted path.
///
class ScalarExpr : public Expr {
public:
/// Create a new ScalarExpr based on thrift Expr 'texpr'. The newly created ScalarExpr
/// is stored in ObjectPool 'pool' and returned in 'expr' on success. 'row_desc' is the
/// tuple row descriptor of the input tuple row. On failure, 'expr' is set to NULL and
/// the expr tree (if created) will be closed. Error status will be returned too.
static Status Create(const TExpr& texpr, const RowDescriptor& row_desc,
RuntimeState* state, ObjectPool* pool, ScalarExpr** expr) WARN_UNUSED_RESULT;
/// Create a new ScalarExpr based on thrift Expr 'texpr'. The newly created ScalarExpr
/// is stored in ObjectPool 'state->obj_pool()' and returned in 'expr'. 'row_desc' is
/// the tuple row descriptor of the input tuple row. Returns error status on failure.
static Status Create(const TExpr& texpr, const RowDescriptor& row_desc,
RuntimeState* state, ScalarExpr** expr) WARN_UNUSED_RESULT;
/// Convenience functions creating multiple ScalarExpr.
static Status Create(const std::vector<TExpr>& texprs, const RowDescriptor& row_desc,
RuntimeState* state, ObjectPool* pool, std::vector<ScalarExpr*>* exprs)
WARN_UNUSED_RESULT;
/// Convenience functions creating multiple ScalarExpr.
static Status Create(const std::vector<TExpr>& texprs, const RowDescriptor& row_desc,
RuntimeState* state, std::vector<ScalarExpr*>* exprs) WARN_UNUSED_RESULT;
/// Returns true if this expression is a SlotRef. Overridden by SlotRef.
virtual bool IsSlotRef() const { return false; }
/// Returns true if this is a literal expression. Overridden by Literal.
virtual bool IsLiteral() const { return false; }
/// Returns true if this expr uses a FunctionContext to track its runtime state.
/// Overridden by exprs which use FunctionContext.
virtual bool HasFnCtx() const { return false; }
/// Returns true if this expr should be treated as a constant expression.
bool is_constant() const { return is_constant_; }
/// Returns the number of SlotRef nodes in the expr tree. If 'slot_ids' is non-null,
/// add the slot ids to it. Overridden by SlotRef.
virtual int GetSlotIds(std::vector<SlotId>* slot_ids = nullptr) const;
/// Returns an llvm::Function* with signature:
/// <subclass of AnyVal> ComputeFn(ScalarExprEvaluator*, const TupleRow*)
///
/// The function should evaluate this expr over 'row' and return the result as the
/// appropriate type of AnyVal. If 'is_codegen_entry_point' is true, then the
/// appropriate setup is performed to make the Get*Val() method on this expr call into
/// a codegen'd implementation of the expression tree. If this expr is only called from
/// codegen'd code via 'fn', 'is_codegen_entry_point' should be false to reduce the
/// number of entry points into codegen'd code and therefore the overhead of
/// compilation. Returns error status on failure.
///
/// This function is invoked either by other codegen functions (e.g. the codegen code
/// of a join) or by RuntimeState::CodegenScalarExprs() which is called from
/// FragmentInstanceState::Open() before LLVM compilation. These two call sites
/// correspond to the two usage patterns in the class comment.
Status GetCodegendComputeFn(LlvmCodeGen* codegen, bool is_codegen_entry_point,
llvm::Function** fn);
/// Simple debug string that provides no expr subclass-specific information
virtual std::string DebugString() const;
static std::string DebugString(const std::vector<ScalarExpr*>& exprs);
std::string DebugString(const std::string& expr_name) const;
/// Computes a memory efficient layout for storing the results of evaluating 'exprs'.
/// The results are assumed to be void* slot types (vs AnyVal types). Varlen data is
/// not included (e.g. there will be space for a StringValue, but not the data
/// referenced by it).
///
/// Returns the number of bytes necessary to store all the results and offsets
/// where the result for each expr should be stored.
///
/// Variable length types are guaranteed to be at the end and 'var_result_begin'
/// will be set the beginning byte offset where variable length results begin.
/// 'var_result_begin' will be set to -1 if there are no variable len types.
static int ComputeResultsLayout(const vector<ScalarExpr*>& exprs, vector<int>* offsets,
int* var_result_begin);
/// Releases cache entries to libCache for all nodes in the ScalarExpr tree.
virtual void Close();
/// Convenience functions for closing a list of ScalarExpr.
static void Close(const std::vector<ScalarExpr*>& exprs);
static const char* LLVM_CLASS_NAME;
protected:
friend class Expr;
friend class AggFn;
friend class AggFnEvaluator;
friend class AndPredicate;
friend class CaseExpr;
friend class CastFormatExpr;
friend class CoalesceExpr;
friend class ConditionalFunctions;
friend class CompoundPredicate;
friend class DecimalFunctions;
friend class DecimalOperators;
friend class HiveUdfCall;
friend class IfExpr;
friend class InPredicate;
friend class IsNotEmptyPredicate;
friend class IsNullExpr;
friend class KuduPartitionExpr;
friend class Literal;
friend class NullLiteral;
friend class OrPredicate;
friend class Predicate;
friend class ScalarExprEvaluator;
friend class ScalarFnCall;
/// For BE tests
friend class ExprTest;
friend class ExprCodegenTest;
friend class HashTableTest;
/// Assigns indices into the FunctionContext vector 'fn_ctxs_' in an evaluator to
/// nodes which need FunctionContext in the tree. 'next_fn_ctx_idx' is the index
/// of the next available entry in the vector. It's updated as this function is
/// called recursively down the tree.
void AssignFnCtxIdx(int* next_fn_ctx_idx);
int fn_ctx_idx() const { return fn_ctx_idx_; }
/// Creates a single ScalarExpr node based on 'texpr_node' and returns it
/// in 'expr'. Return error status on failure.
static Status CreateNode(const TExprNode& texpr_node, ObjectPool* pool,
ScalarExpr** expr) WARN_UNUSED_RESULT;
ScalarExpr(const ColumnType& type, bool is_constant);
ScalarExpr(const TExprNode& node);
/// Implementation of GetCodegendComputeFn() to be overridden by each subclass of
/// ScalarExpr.
virtual Status GetCodegendComputeFnImpl(
LlvmCodeGen* codegen, llvm::Function** fn) WARN_UNUSED_RESULT = 0;
/// Entry points for ScalarExprEvaluator when interpreting this ScalarExpr. These
/// dispatch to the codegen'd function pointer if present, or otherwise use the
/// Get*ValInterpreted() implementation.
/// These functions should be called by other ScalarExprs and ScalarExprEvaluator only.
BooleanVal GetBooleanVal(ScalarExprEvaluator*, const TupleRow*) const;
TinyIntVal GetTinyIntVal(ScalarExprEvaluator*, const TupleRow*) const;
SmallIntVal GetSmallIntVal(ScalarExprEvaluator*, const TupleRow*) const;
IntVal GetIntVal(ScalarExprEvaluator*, const TupleRow*) const;
BigIntVal GetBigIntVal(ScalarExprEvaluator*, const TupleRow*) const;
FloatVal GetFloatVal(ScalarExprEvaluator*, const TupleRow*) const;
DoubleVal GetDoubleVal(ScalarExprEvaluator*, const TupleRow*) const;
StringVal GetStringVal(ScalarExprEvaluator*, const TupleRow*) const;
CollectionVal GetCollectionVal(ScalarExprEvaluator*, const TupleRow*) const;
TimestampVal GetTimestampVal(ScalarExprEvaluator*, const TupleRow*) const;
DecimalVal GetDecimalVal(ScalarExprEvaluator*, const TupleRow*) const;
DateVal GetDateVal(ScalarExprEvaluator*, const TupleRow*) const;
/// Virtual compute functions for each return type. Each subclass should override
/// the functions for the return type(s) it supports. For example, a boolean function
/// will only override GetBooleanValInterpreted(). Some Exprs, like Literal, have many
/// possible return types and will override multiple Get*ValInterpreted() functions.
virtual BooleanVal GetBooleanValInterpreted(
ScalarExprEvaluator*, const TupleRow*) const;
virtual TinyIntVal GetTinyIntValInterpreted(
ScalarExprEvaluator*, const TupleRow*) const;
virtual SmallIntVal GetSmallIntValInterpreted(
ScalarExprEvaluator*, const TupleRow*) const;
virtual IntVal GetIntValInterpreted(ScalarExprEvaluator*, const TupleRow*) const;
virtual BigIntVal GetBigIntValInterpreted(ScalarExprEvaluator*, const TupleRow*) const;
virtual FloatVal GetFloatValInterpreted(ScalarExprEvaluator*, const TupleRow*) const;
virtual DoubleVal GetDoubleValInterpreted(ScalarExprEvaluator*, const TupleRow*) const;
virtual StringVal GetStringValInterpreted(ScalarExprEvaluator*, const TupleRow*) const;
virtual CollectionVal GetCollectionValInterpreted(
ScalarExprEvaluator*, const TupleRow*) const;
virtual TimestampVal GetTimestampValInterpreted(
ScalarExprEvaluator*, const TupleRow*) const;
virtual DecimalVal GetDecimalValInterpreted(
ScalarExprEvaluator*, const TupleRow*) const;
virtual DateVal GetDateValInterpreted(ScalarExprEvaluator*, const TupleRow*) const;
/// Initializes all nodes in the expr tree. Subclasses overriding this function must
/// call ScalarExpr::Init(). If 'is_entry_point' is true, this indicates that Get*Val()
/// may be called directly from interpreted code and that we should generate an entry
/// point into the codegen'd code. Currently we assume all roots of ScalarExpr subtrees
/// exprs are potential entry points.
virtual Status Init(const RowDescriptor& row_desc, bool is_entry_point,
RuntimeState* state) WARN_UNUSED_RESULT;
/// Initializes 'eval' for execution. If scope if FRAGMENT_LOCAL, both
/// fragment-local and thread-local states should be initialized. If scope is
/// THREAD_LOCAL, only thread-local states should be initialized. THREAD_LOCAL
/// scope is used for cloned evaluator.
///
/// Subclasses overriding this function should call ScalarExpr::OpenEvaluator() to
/// recursively call OpenEvaluator() on all nodes in the ScalarExpr tree.
virtual Status OpenEvaluator(FunctionContext::FunctionStateScope scope,
RuntimeState* state, ScalarExprEvaluator* eval) const
WARN_UNUSED_RESULT;
/// Free resources held by the 'eval' allocated during OpenEvaluator().
/// If scope is FRAGMENT_LOCAL, both fragment-local and thread-local states should be
/// torn down. If scope is THREAD_LOCAL, only thread-local state should be torn down.
///
/// Subclasses overriding this function should call ScalarExpr::CloseEvaluator() to
/// recursively call CloseEvaluator() on all nodes in the ScalarExpr tree.
virtual void CloseEvaluator(FunctionContext::FunctionStateScope scope,
RuntimeState* state, ScalarExprEvaluator* eval) const;
/// Computes the size of the varargs buffer in bytes (0 bytes if no varargs).
/// Overridden by ScalarFnCall.
virtual int ComputeVarArgsBufferSize() const { return 0; }
/// Helper function to create an empty llvm::Function* with the signature:
/// *Val name(ScalarExprEvaluator*, TupleRow*);
///
/// 'name' is the name of the returned llvm::Function*. The arguments to the IR function
/// are returned in 'args'. The return type is determined by the return type of the expr
/// tree.
llvm::Function* CreateIrFunctionPrototype(const std::string& name, LlvmCodeGen* codegen,
llvm::Value* (*args)[2]);
/// Generates an IR compute function that calls the interpreted compute function.
/// It doesn't provide any performance benefit over the interpreted path. This is
/// useful for builtins (e.g. && and || operators) and UDF which don't generate
/// custom IR code but are part of a larger expr tree. The IR compute function of
/// the larger expr tree may still benefit from custom IR and inlining of other
/// sub-expressions.
///
/// TODO: this should be removed in the long run and replaced with cross-compilation
/// together with constant propagation and loop unrolling.
Status GetCodegendComputeFnWrapper(LlvmCodeGen* codegen, llvm::Function** fn)
WARN_UNUSED_RESULT;
/// Helper function for GetCodegendComputeFnWrapper(). Returns the cross-compiled IR
/// function of the static Get*Val wrapper function for return type 'type'. Must not
/// be called for a type that doesn't have a wrapper function in the built-in
/// IR module. Never returns NULL.
llvm::Function* GetStaticGetValWrapper(ColumnType type, LlvmCodeGen* codegen);
protected:
/// Return true if we should codegen this expression node, based on query options
/// and the properties of this ScalarExpr node.
bool ShouldCodegen(const RuntimeState* state) const;
/// Return true if it is possible to evaluate this expression node without codegen.
/// The vast majority of exprs support interpretation, so default to true. Scalars
/// that are not always interpretable must override this function.
virtual bool IsInterpretable() const { return true; }
private:
/// 'fn_ctx_idx_' is the index into the FunctionContext vector in ScalarExprEvaluator
/// for storing FunctionContext needed to evaluate this ScalarExprNode. It's -1 if this
/// ScalarExpr doesn't need a FunctionContext. The FunctionContext is managed by the
/// evaluator and initialized by calling ScalarExpr::OpenEvaluator().
int fn_ctx_idx_ = -1;
/// [fn_ctx_idx_start_, fn_ctx_idx_end_) defines the range in FunctionContext vector
/// in ScalarExpeEvaluator for the expression subtree rooted at this ScalarExpr node.
int fn_ctx_idx_start_ = 0;
int fn_ctx_idx_end_ = 0;
/// True if this expr should be treated as a constant expression. True if either:
/// * This expr was sent from the frontend and Expr.isConstant() was true.
/// * This expr is a constant literal created in the backend.
const bool is_constant_;
/// Cached LLVM IR for the compute function. Set in GetCodegendComputeFn().
llvm::Function* ir_compute_fn_ = nullptr;
/// Function pointer to the JIT'd function produced by GetCodegendComputeFn().
/// Has signature *Val (ScalarExprEvaluator*, const TupleRow*), and calls the scalar
/// function with signature like *Val (FunctionContext*, const *Val& arg1, ...)
/// Non-NULL if this expr is codegen'd and the constructor of this Expr requested
/// that this expr should be an entry point from interpreted to codegen'd code.
/// (see class comment for explanation of usage patterns and motivation).
void* codegend_compute_fn_ = nullptr;
/// True if 'codegend_compute_fn_' is registered with LlvmCodeGen as an entry point
/// to codegen to fill in . If this is true, then 'codegend_compute_fn_' will be set
/// to the JIT'd function produced by GetCodegendComputeFn() after LLVM compilation.
/// Set in GetCodegendComputeFn().
bool added_to_jit_ = false;
/// Static wrappers which call the compute function of the given ScalarExpr, passing
/// it the ScalarExprEvaluator and TupleRow. These are cross-compiled and called by
/// the IR wrapper functions generated by GetCodegendComputeFnWrapper(). The wrapper
/// functions avoid the need for codegen'd callers to do a virtual function call on
/// the ScalarExpr.
/// Note: the ScalarExpr subclass is known at codegen time, so codegen *could* replace
/// the virtual function call with a direct function call. However, it would be better
/// to focus on removing GetCodegendComputeFnWrapper() instead of micro-optimising this
/// inefficient mechanism.
static BooleanVal GetBooleanValInterpreted(
ScalarExpr*, ScalarExprEvaluator*, const TupleRow*);
static TinyIntVal GetTinyIntValInterpreted(
ScalarExpr*, ScalarExprEvaluator*, const TupleRow*);
static SmallIntVal GetSmallIntValInterpreted(
ScalarExpr*, ScalarExprEvaluator*, const TupleRow*);
static IntVal GetIntValInterpreted(ScalarExpr*, ScalarExprEvaluator*, const TupleRow*);
static BigIntVal GetBigIntValInterpreted(
ScalarExpr*, ScalarExprEvaluator*, const TupleRow*);
static FloatVal GetFloatValInterpreted(
ScalarExpr*, ScalarExprEvaluator*, const TupleRow*);
static DoubleVal GetDoubleValInterpreted(
ScalarExpr*, ScalarExprEvaluator*, const TupleRow*);
static StringVal GetStringValInterpreted(
ScalarExpr*, ScalarExprEvaluator*, const TupleRow*);
static TimestampVal GetTimestampValInterpreted(
ScalarExpr*, ScalarExprEvaluator*, const TupleRow*);
static DecimalVal GetDecimalValInterpreted(
ScalarExpr*, ScalarExprEvaluator*, const TupleRow*);
static DateVal GetDateValInterpreted(
ScalarExpr*, ScalarExprEvaluator*, const TupleRow*);
};
// Helper to generate the declaration for an override of Get*ValInterpreted()
#define GET_VAL_INTERPRETED_OVERRIDE(val_type) \
virtual val_type Get##val_type##Interpreted(ScalarExprEvaluator*, const TupleRow*) \
const override;
// Helper to stamp out Get*ValInterpreted() declarations for all scalar types.
#define GENERATE_GET_VAL_INTERPRETED_OVERRIDES_FOR_ALL_SCALAR_TYPES \
GET_VAL_INTERPRETED_OVERRIDE(BooleanVal) \
GET_VAL_INTERPRETED_OVERRIDE(TinyIntVal) \
GET_VAL_INTERPRETED_OVERRIDE(SmallIntVal) \
GET_VAL_INTERPRETED_OVERRIDE(IntVal) \
GET_VAL_INTERPRETED_OVERRIDE(BigIntVal) \
GET_VAL_INTERPRETED_OVERRIDE(FloatVal) \
GET_VAL_INTERPRETED_OVERRIDE(DoubleVal) \
GET_VAL_INTERPRETED_OVERRIDE(StringVal) \
GET_VAL_INTERPRETED_OVERRIDE(TimestampVal) \
GET_VAL_INTERPRETED_OVERRIDE(DecimalVal) \
GET_VAL_INTERPRETED_OVERRIDE(DateVal)
} // namespace impala
#endif