Remove llvm relative code from be/src/exec (#2955)

Remove unused LLVM related codes of directory:be/src/exec (#2910)

there are many LLVM related codes in code base, but these codes are not really used.
The higher version of GCC is not compatible with the LLVM 3.4.2 version currently used by Doris.
The PR delete all LLVM related code of directory: be/src/exec.
This commit is contained in:
trueeyu
2020-02-20 20:43:26 +08:00
committed by GitHub
parent da945c8278
commit 839ec45197
23 changed files with 0 additions and 3947 deletions

View File

@ -24,7 +24,6 @@
#include <gperftools/profiler.h>
#include "codegen/codegen_anyval.h"
#include "codegen/llvm_codegen.h"
#include "exec/hash_table.hpp"
#include "exprs/agg_fn_evaluator.h"
#include "exprs/expr.h"
@ -41,17 +40,8 @@
#include "runtime/tuple_row.h"
#include "util/runtime_profile.h"
using llvm::BasicBlock;
using llvm::Function;
using llvm::PointerType;
using llvm::Type;
using llvm::Value;
using llvm::StructType;
namespace doris {
const char* AggregationNode::_s_llvm_class_name = "class.doris::AggregationNode";
// TODO: pass in maximum size; enforce by setting limit in mempool
// TODO: have a Status ExecNode::init(const TPlanNode&) member function
// that does initialization outside of c'tor, so we can indicate errors
@ -65,7 +55,6 @@ AggregationNode::AggregationNode(
_singleton_output_tuple(NULL),
//_tuple_pool(new MemPool()),
//
_codegen_process_row_batch_fn(NULL),
_process_row_batch_fn(NULL),
_needs_finalize(tnode.agg_node.need_finalize),
_build_timer(NULL),
@ -156,22 +145,6 @@ Status AggregationNode::prepare(RuntimeState* state) {
_singleton_output_tuple = construct_intermediate_tuple();
}
if (state->codegen_level() > 0) {
LlvmCodeGen* codegen = NULL;
RETURN_IF_ERROR(state->get_codegen(&codegen));
Function* update_tuple_fn = codegen_update_tuple(state);
if (update_tuple_fn != NULL) {
_codegen_process_row_batch_fn =
codegen_process_row_batch(state, update_tuple_fn);
if (_codegen_process_row_batch_fn != NULL) {
// Update to using codegen'd process row batch.
codegen->add_function_to_jit(_codegen_process_row_batch_fn,
reinterpret_cast<void**>(&_process_row_batch_fn));
// AddRuntimeExecOption("Codegen Enabled");
}
}
}
return Status::OK();
}
@ -481,539 +454,5 @@ void AggregationNode::push_down_predicate(RuntimeState *state,
return;
}
static IRFunction::Type get_hll_update_function2(const TypeDescriptor& type) {
switch (type.type) {
case TYPE_BOOLEAN:
return IRFunction::HLL_UPDATE_BOOLEAN;
case TYPE_TINYINT:
return IRFunction::HLL_UPDATE_TINYINT;
case TYPE_SMALLINT:
return IRFunction::HLL_UPDATE_SMALLINT;
case TYPE_INT:
return IRFunction::HLL_UPDATE_INT;
case TYPE_BIGINT:
return IRFunction::HLL_UPDATE_BIGINT;
case TYPE_FLOAT:
return IRFunction::HLL_UPDATE_FLOAT;
case TYPE_DOUBLE:
return IRFunction::HLL_UPDATE_DOUBLE;
case TYPE_CHAR:
case TYPE_VARCHAR:
return IRFunction::HLL_UPDATE_STRING;
case TYPE_DECIMAL:
return IRFunction::HLL_UPDATE_DECIMAL;
default:
DCHECK(false) << "Unsupported type: " << type;
return IRFunction::FN_END;
}
}
// IR Generation for updating a single aggregation slot. Signature is:
// void update_slot(FunctionContext* fn_ctx, AggTuple* agg_tuple, char** row)
//
// The IR for sum(double_col) is:
// define void @update_slot(%"class.doris_udf::FunctionContext"* %fn_ctx,
// { i8, double }* %agg_tuple,
// %"class.doris::TupleRow"* %row) #20 {
// entry:
// %src = call { i8, double } @GetSlotRef(%"class.doris::ExprContext"* inttoptr
// (i64 128241264 to %"class.doris::ExprContext"*), %"class.doris::TupleRow"* %row)
// %0 = extractvalue { i8, double } %src, 0
// %is_null = trunc i8 %0 to i1
// br i1 %is_null, label %ret, label %src_not_null
//
// src_not_null: ; preds = %entry
// %dst_slot_ptr = getelementptr inbounds { i8, double }* %agg_tuple, i32 0, i32 1
// call void @SetNotNull({ i8, double }* %agg_tuple)
// %dst_val = load double* %dst_slot_ptr
// %val = extractvalue { i8, double } %src, 1
// %1 = fadd double %dst_val, %val
// store double %1, double* %dst_slot_ptr
// br label %ret
//
// ret: ; preds = %src_not_null, %entry
// ret void
// }
//
// The IR for min(double_col) is:
// define void @update_slot(%"class.doris_udf::FunctionContext"* %fn_ctx,
// { i8, double }* %agg_tuple,
// %"class.doris::TupleRow"* %row) #20 {
// entry:
// %src = call { i8, double } @GetSlotRef(%"class.doris::ExprContext"* inttoptr
// (i64 128241264 to %"class.doris::ExprContext"*), %"class.doris::TupleRow"* %row)
// %0 = extractvalue { i8, double } %src, 0
// %is_null = trunc i8 %0 to i1
// br i1 %is_null, label %ret, label %src_not_null
//
// src_not_null: ; preds = %entry
// %dst_is_null = call i8 @is_null(tuple);
// br i1 %dst_is_null, label dst_null, label dst_not_null
//
// dst_null: ; preds = %entry
// %dst_slot_ptr = getelementptr inbounds { i8, double }* %agg_tuple, i32 0, i32 1
// call void @SetNotNull({ i8, double }* %agg_tuple)
// %val = extractvalue { i8, double } %src, 1
// store double %val, double* %dst_slot_ptr
// br label %ret
//
// dst_not_null: ; preds = %src_not_null
// %dst_slot_ptr = getelementptr inbounds { i8, double }* %agg_tuple, i32 0, i32 1
// call void @SetNotNull({ i8, double }* %agg_tuple)
// %dst_val = load double* %dst_slot_ptr
// %val = extractvalue { i8, double } %src, 1
// %1 = fadd double %dst_val, %val
// store double %1, double* %dst_slot_ptr
// br label %ret
//
// ret: ; preds = %src_not_null, %entry
// ret void
// }
// The IR for ndv(double_col) is:
// define void @update_slot(%"class.doris_udf::FunctionContext"* %fn_ctx,
// { i8, %"struct.doris::StringValue" }* %agg_tuple,
// %"class.doris::TupleRow"* %row) #20 {
// entry:
// %dst_lowered_ptr = alloca { i64, i8* }
// %src_lowered_ptr = alloca { i8, double }
// %src = call { i8, double } @GetSlotRef(%"class.doris::ExprContext"* inttoptr
// (i64 120530832 to %"class.doris::ExprContext"*), %"class.doris::TupleRow"* %row)
// %0 = extractvalue { i8, double } %src, 0
// %is_null = trunc i8 %0 to i1
// br i1 %is_null, label %ret, label %src_not_null
//
// src_not_null: ; preds = %entry
// %dst_slot_ptr = getelementptr inbounds
// { i8, %"struct.doris::StringValue" }* %agg_tuple, i32 0, i32 1
// call void @SetNotNull({ i8, %"struct.doris::StringValue" }* %agg_tuple)
// %dst_val = load %"struct.doris::StringValue"* %dst_slot_ptr
// store { i8, double } %src, { i8, double }* %src_lowered_ptr
// %src_unlowered_ptr = bitcast { i8, double }* %src_lowered_ptr
// to %"struct.doris_udf::DoubleVal"*
// %ptr = extractvalue %"struct.doris::StringValue" %dst_val, 0
// %dst_stringval = insertvalue { i64, i8* } zeroinitializer, i8* %ptr, 1
// %len = extractvalue %"struct.doris::StringValue" %dst_val, 1
// %1 = extractvalue { i64, i8* } %dst_stringval, 0
// %2 = zext i32 %len to i64
// %3 = shl i64 %2, 32
// %4 = and i64 %1, 4294967295
// %5 = or i64 %4, %3
// %dst_stringval1 = insertvalue { i64, i8* } %dst_stringval, i64 %5, 0
// store { i64, i8* } %dst_stringval1, { i64, i8* }* %dst_lowered_ptr
// %dst_unlowered_ptr = bitcast { i64, i8* }* %dst_lowered_ptr
// to %"struct.doris_udf::StringVal"*
// call void @HllUpdate(%"class.doris_udf::FunctionContext"* %fn_ctx,
// %"struct.doris_udf::DoubleVal"* %src_unlowered_ptr,
// %"struct.doris_udf::StringVal"* %dst_unlowered_ptr)
// %anyval_result = load { i64, i8* }* %dst_lowered_ptr
// %6 = extractvalue { i64, i8* } %anyval_result, 1
// %7 = insertvalue %"struct.doris::StringValue" zeroinitializer, i8* %6, 0
// %8 = extractvalue { i64, i8* } %anyval_result, 0
// %9 = ashr i64 %8, 32
// %10 = trunc i64 %9 to i32
// %11 = insertvalue %"struct.doris::StringValue" %7, i32 %10, 1
// store %"struct.doris::StringValue" %11, %"struct.doris::StringValue"* %dst_slot_ptr
// br label %ret
//
// ret: ; preds = %src_not_null, %entry
// ret void
// }
llvm::Function* AggregationNode::codegen_update_slot(
RuntimeState* state, AggFnEvaluator* evaluator, SlotDescriptor* slot_desc) {
DCHECK(slot_desc->is_materialized());
LlvmCodeGen* codegen = NULL;
if (!state->get_codegen(&codegen).ok()) {
return NULL;
}
DCHECK_EQ(evaluator->input_expr_ctxs().size(), 1);
ExprContext* input_expr_ctx = evaluator->input_expr_ctxs()[0];
Expr* input_expr = input_expr_ctx->root();
// TODO: implement timestamp
if (input_expr->type().type == TYPE_DATETIME
|| input_expr->type().type == TYPE_DATE
|| input_expr->type().type == TYPE_DECIMAL
|| input_expr->type().is_string_type()) {
return NULL;
}
Function* agg_expr_fn = NULL;
Status status = input_expr->get_codegend_compute_fn(state, &agg_expr_fn);
if (!status.ok()) {
LOG(INFO) << "Could not codegen update_slot(): " << status.get_error_msg();
return NULL;
}
DCHECK(agg_expr_fn != NULL);
PointerType* fn_ctx_type =
codegen->get_ptr_type(FunctionContextImpl::_s_llvm_functioncontext_name);
StructType* tuple_struct = _intermediate_tuple_desc->generate_llvm_struct(codegen);
PointerType* tuple_ptr_type = PointerType::get(tuple_struct, 0);
PointerType* tuple_row_ptr_type = codegen->get_ptr_type(TupleRow::_s_llvm_class_name);
// Create update_slot prototype
LlvmCodeGen::FnPrototype prototype(codegen, "update_slot", codegen->void_type());
prototype.add_argument(LlvmCodeGen::NamedVariable("fn_ctx", fn_ctx_type));
prototype.add_argument(LlvmCodeGen::NamedVariable("agg_tuple", tuple_ptr_type));
prototype.add_argument(LlvmCodeGen::NamedVariable("row", tuple_row_ptr_type));
LlvmCodeGen::LlvmBuilder builder(codegen->context());
Value* args[3];
Function* fn = prototype.generate_prototype(&builder, &args[0]);
Value* fn_ctx_arg = args[0];
Value* agg_tuple_arg = args[1];
Value* row_arg = args[2];
BasicBlock* src_not_null_block = NULL;
BasicBlock* dst_null_block = NULL;
BasicBlock* dst_not_null_block = NULL;
if (evaluator->agg_op() == AggFnEvaluator::MIN
|| evaluator->agg_op() == AggFnEvaluator::MAX) {
src_not_null_block = BasicBlock::Create(codegen->context(), "src_not_null", fn);
dst_null_block = BasicBlock::Create(codegen->context(), "dst_null", fn);
}
dst_not_null_block = BasicBlock::Create(codegen->context(), "dst_not_null", fn);
BasicBlock* ret_block = BasicBlock::Create(codegen->context(), "ret", fn);
// Call expr function to get src slot value
Value* ctx_arg = codegen->cast_ptr_to_llvm_ptr(
codegen->get_ptr_type(ExprContext::_s_llvm_class_name), input_expr_ctx);
Value* agg_expr_fn_args[] = { ctx_arg, row_arg };
CodegenAnyVal src = CodegenAnyVal::create_call_wrapped(
codegen, &builder, input_expr->type(), agg_expr_fn, agg_expr_fn_args, "src", NULL);
Value* src_is_null = src.get_is_null();
if (evaluator->agg_op() == AggFnEvaluator::MIN
|| evaluator->agg_op() == AggFnEvaluator::MAX) {
builder.CreateCondBr(src_is_null, ret_block, src_not_null_block);
// Src slot is not null
builder.SetInsertPoint(src_not_null_block);
Function* is_null_fn = slot_desc->codegen_is_null(codegen, tuple_struct);
Value* dst_is_null = builder.CreateCall(is_null_fn, agg_tuple_arg);
builder.CreateCondBr(dst_is_null, dst_null_block, dst_not_null_block);
// dst slot is null
builder.SetInsertPoint(dst_null_block);
Value* dst_ptr =
builder.CreateStructGEP(agg_tuple_arg, slot_desc->field_idx(), "dst_slot_ptr");
if (slot_desc->is_nullable()) {
// Dst is NULL, just update dst slot to src slot and clear null bit
Function* clear_null_fn = slot_desc->codegen_update_null(codegen, tuple_struct, false);
builder.CreateCall(clear_null_fn, agg_tuple_arg);
}
builder.CreateStore(src.get_val(), dst_ptr);
builder.CreateBr(ret_block);
} else {
builder.CreateCondBr(src_is_null, ret_block, dst_not_null_block);
}
// Src slot is not null, update dst_slot
builder.SetInsertPoint(dst_not_null_block);
Value* dst_ptr =
builder.CreateStructGEP(agg_tuple_arg, slot_desc->field_idx(), "dst_slot_ptr");
Value* result = NULL;
if (slot_desc->is_nullable()) {
// Dst is NULL, just update dst slot to src slot and clear null bit
Function* clear_null_fn = slot_desc->codegen_update_null(codegen, tuple_struct, false);
builder.CreateCall(clear_null_fn, agg_tuple_arg);
}
// Update the slot
Value* dst_value = builder.CreateLoad(dst_ptr, "dst_val");
switch (evaluator->agg_op()) {
case AggFnEvaluator::COUNT:
if (evaluator->is_merge()) {
result = builder.CreateAdd(dst_value, src.get_val(), "count_sum");
} else {
result = builder.CreateAdd(
dst_value, codegen->get_int_constant(TYPE_BIGINT, 1), "count_inc");
}
break;
case AggFnEvaluator::MIN: {
Function* min_fn = codegen->codegen_min_max(slot_desc->type(), true);
Value* min_args[] = { dst_value, src.get_val() };
result = builder.CreateCall(min_fn, min_args, "min_value");
break;
}
case AggFnEvaluator::MAX: {
Function* max_fn = codegen->codegen_min_max(slot_desc->type(), false);
Value* max_args[] = { dst_value, src.get_val() };
result = builder.CreateCall(max_fn, max_args, "max_value");
break;
}
case AggFnEvaluator::SUM:
if (slot_desc->type().type == TYPE_FLOAT || slot_desc->type().type == TYPE_DOUBLE) {
result = builder.CreateFAdd(dst_value, src.get_val());
} else {
result = builder.CreateAdd(dst_value, src.get_val());
}
break;
case AggFnEvaluator::NDV: {
DCHECK_EQ(slot_desc->type().type, TYPE_VARCHAR);
IRFunction::Type ir_function_type = evaluator->is_merge() ? IRFunction::HLL_MERGE
: get_hll_update_function2(input_expr->type());
Function* hll_fn = codegen->get_function(ir_function_type);
// Create pointer to src_anyval to pass to HllUpdate() function. We must use the
// unlowered type.
Value* src_lowered_ptr = codegen->create_entry_block_alloca(
fn, LlvmCodeGen::NamedVariable("src_lowered_ptr", src.value()->getType()));
builder.CreateStore(src.value(), src_lowered_ptr);
Type* unlowered_ptr_type =
CodegenAnyVal::get_unlowered_type(codegen, input_expr->type())->getPointerTo();
Value* src_unlowered_ptr =
builder.CreateBitCast(src_lowered_ptr, unlowered_ptr_type, "src_unlowered_ptr");
// Create StringVal* intermediate argument from dst_value
CodegenAnyVal dst_stringval = CodegenAnyVal::get_non_null_val(
codegen, &builder, TypeDescriptor(TYPE_VARCHAR), "dst_stringval");
dst_stringval.set_from_raw_value(dst_value);
// Create pointer to dst_stringval to pass to HllUpdate() function. We must use
// the unlowered type.
Value* dst_lowered_ptr = codegen->create_entry_block_alloca(
fn, LlvmCodeGen::NamedVariable("dst_lowered_ptr",
dst_stringval.value()->getType()));
builder.CreateStore(dst_stringval.value(), dst_lowered_ptr);
unlowered_ptr_type =
codegen->get_ptr_type(CodegenAnyVal::get_unlowered_type(
codegen, TypeDescriptor(TYPE_VARCHAR)));
Value* dst_unlowered_ptr =
builder.CreateBitCast(dst_lowered_ptr, unlowered_ptr_type, "dst_unlowered_ptr");
// Call 'hll_fn'
builder.CreateCall3(hll_fn, fn_ctx_arg, src_unlowered_ptr, dst_unlowered_ptr);
// Convert StringVal intermediate 'dst_arg' back to StringValue
Value* anyval_result = builder.CreateLoad(dst_lowered_ptr, "anyval_result");
result = CodegenAnyVal(codegen, &builder, TypeDescriptor(TYPE_VARCHAR), anyval_result)
.to_native_value();
break;
}
default:
DCHECK(false) << "bad aggregate operator: " << evaluator->agg_op();
}
builder.CreateStore(result, dst_ptr);
builder.CreateBr(ret_block);
builder.SetInsertPoint(ret_block);
builder.CreateRetVoid();
fn = codegen->finalize_function(fn);
return fn;
}
// IR codegen for the update_tuple loop. This loop is query specific and
// based on the aggregate functions. The function signature must match the non-
// codegen'd update_tuple exactly.
// For the query:
// select count(*), count(int_col), sum(double_col) the IR looks like:
//
// define void @update_tuple(%"class.doris::AggregationNode"* %this_ptr,
// %"class.doris::Tuple"* %agg_tuple,
// %"class.doris::TupleRow"* %tuple_row) #20 {
// entry:
// %tuple = bitcast %"class.doris::Tuple"* %agg_tuple to { i8, i64, i64, double }*
// %src_slot = getelementptr inbounds { i8, i64, i64, double }* %tuple, i32 0, i32 1
// %count_star_val = load i64* %src_slot
// %count_star_inc = add i64 %count_star_val, 1
// store i64 %count_star_inc, i64* %src_slot
// call void @update_slot(%"class.doris_udf::FunctionContext"* inttoptr
// (i64 44521296 to %"class.doris_udf::FunctionContext"*),
// { i8, i64, i64, double }* %tuple,
// %"class.doris::TupleRow"* %tuple_row)
// call void @UpdateSlot5(%"class.doris_udf::FunctionContext"* inttoptr
// (i64 44521328 to %"class.doris_udf::FunctionContext"*),
// { i8, i64, i64, double }* %tuple,
// %"class.doris::TupleRow"* %tuple_row)
// ret void
// }
Function* AggregationNode::codegen_update_tuple(RuntimeState* state) {
LlvmCodeGen* codegen = NULL;
if (!state->get_codegen(&codegen).ok()) {
return NULL;
}
SCOPED_TIMER(codegen->codegen_timer());
int j = _probe_expr_ctxs.size();
for (int i = 0; i < _aggregate_evaluators.size(); ++i, ++j) {
// skip non-materialized slots; we don't have evaluators instantiated for those
while (!_intermediate_tuple_desc->slots()[j]->is_materialized()) {
DCHECK_LT(j, _intermediate_tuple_desc->slots().size() - 1);
++j;
}
SlotDescriptor* slot_desc = _intermediate_tuple_desc->slots()[j];
AggFnEvaluator* evaluator = _aggregate_evaluators[i];
// Timestamp and char are never supported. NDV supports decimal and string but no
// other functions.
// TODO: the other aggregate functions might work with decimal as-is
// TODO(zc)
if (slot_desc->type().type == TYPE_DATETIME || slot_desc->type().type == TYPE_CHAR ||
(evaluator->agg_op() != AggFnEvaluator::NDV &&
(slot_desc->type().type == TYPE_DECIMAL ||
slot_desc->type().type == TYPE_CHAR ||
slot_desc->type().type == TYPE_VARCHAR))) {
LOG(INFO) << "Could not codegen UpdateIntermediateTuple because "
<< "string, char, timestamp and decimal are not yet supported.";
return NULL;
}
if (evaluator->agg_op() == AggFnEvaluator::COUNT_DISTINCT
|| evaluator->agg_op() == AggFnEvaluator::SUM_DISTINCT) {
return NULL;
}
// Don't codegen things that aren't builtins (for now)
if (!evaluator->is_builtin()) {
return NULL;
}
}
if (_intermediate_tuple_desc->generate_llvm_struct(codegen) == NULL) {
LOG(INFO) << "Could not codegen update_tuple because we could"
<< "not generate a matching llvm struct for the intermediate tuple.";
return NULL;
}
// Get the types to match the update_tuple signature
Type* agg_node_type = codegen->get_type(AggregationNode::_s_llvm_class_name);
Type* agg_tuple_type = codegen->get_type(Tuple::_s_llvm_class_name);
Type* tuple_row_type = codegen->get_type(TupleRow::_s_llvm_class_name);
DCHECK(agg_node_type != NULL);
DCHECK(agg_tuple_type != NULL);
DCHECK(tuple_row_type != NULL);
PointerType* agg_node_ptr_type = PointerType::get(agg_node_type, 0);
PointerType* agg_tuple_ptr_type = PointerType::get(agg_tuple_type, 0);
PointerType* tuple_row_ptr_type = PointerType::get(tuple_row_type, 0);
// Signature for update_tuple is
// void update_tuple(AggregationNode* this, Tuple* tuple, TupleRow* row)
// This signature needs to match the non-codegen'd signature exactly.
StructType* tuple_struct = _intermediate_tuple_desc->generate_llvm_struct(codegen);
PointerType* tuple_ptr = PointerType::get(tuple_struct, 0);
LlvmCodeGen::FnPrototype prototype(codegen, "update_tuple", codegen->void_type());
prototype.add_argument(LlvmCodeGen::NamedVariable("this_ptr", agg_node_ptr_type));
prototype.add_argument(LlvmCodeGen::NamedVariable("agg_tuple", agg_tuple_ptr_type));
prototype.add_argument(LlvmCodeGen::NamedVariable("tuple_row", tuple_row_ptr_type));
LlvmCodeGen::LlvmBuilder builder(codegen->context());
Value* args[3];
Function* fn = prototype.generate_prototype(&builder, &args[0]);
// Cast the parameter types to the internal llvm runtime types.
// TODO: get rid of this by using right type in function signature
args[1] = builder.CreateBitCast(args[1], tuple_ptr, "tuple");
// Loop over each expr and generate the IR for that slot. If the expr is not
// count(*), generate a helper IR function to update the slot and call that.
j = _probe_expr_ctxs.size();
for (int i = 0; i < _aggregate_evaluators.size(); ++i, ++j) {
// skip non-materialized slots; we don't have evaluators instantiated for those
while (!_intermediate_tuple_desc->slots()[j]->is_materialized()) {
DCHECK_LT(j, _intermediate_tuple_desc->slots().size() - 1);
++j;
}
SlotDescriptor* slot_desc = _intermediate_tuple_desc->slots()[j];
AggFnEvaluator* evaluator = _aggregate_evaluators[i];
if (evaluator->is_count_star()) {
// TODO: we should be able to hoist this up to the loop over the batch and just
// increment the slot by the number of rows in the batch.
int field_idx = slot_desc->field_idx();
Value* const_one = codegen->get_int_constant(TYPE_BIGINT, 1);
Value* slot_ptr = builder.CreateStructGEP(args[1], field_idx, "src_slot");
Value* slot_loaded = builder.CreateLoad(slot_ptr, "count_star_val");
Value* count_inc = builder.CreateAdd(slot_loaded, const_one, "count_star_inc");
builder.CreateStore(count_inc, slot_ptr);
} else {
Function* update_slot_fn = codegen_update_slot(state, evaluator, slot_desc);
if (update_slot_fn == NULL) {
return NULL;
}
Value* fn_ctx_arg = codegen->cast_ptr_to_llvm_ptr(
codegen->get_ptr_type(FunctionContextImpl::_s_llvm_functioncontext_name),
_agg_fn_ctxs[i]);
builder.CreateCall3(update_slot_fn, fn_ctx_arg, args[1], args[2]);
}
}
builder.CreateRetVoid();
// CodegenProcessRowBatch() does the final optimizations.
return codegen->finalize_function(fn);
}
Function* AggregationNode::codegen_process_row_batch(
RuntimeState* state, Function* update_tuple_fn) {
LlvmCodeGen* codegen = NULL;
if (!state->get_codegen(&codegen).ok()) {
return NULL;
}
SCOPED_TIMER(codegen->codegen_timer());
DCHECK(update_tuple_fn != NULL);
// Get the cross compiled update row batch function
IRFunction::Type ir_fn =
(!_probe_expr_ctxs.empty() ? IRFunction::AGG_NODE_PROCESS_ROW_BATCH_WITH_GROUPING
: IRFunction::AGG_NODE_PROCESS_ROW_BATCH_NO_GROUPING);
Function* process_batch_fn = codegen->get_function(ir_fn);
if (process_batch_fn == NULL) {
LOG(ERROR) << "Could not find AggregationNode::ProcessRowBatch in module.";
return NULL;
}
int replaced = 0;
if (!_probe_expr_ctxs.empty()) {
// Aggregation w/o grouping does not use a hash table.
// Codegen for hash
Function* hash_fn = _hash_tbl->codegen_hash_current_row(state);
if (hash_fn == NULL) {
return NULL;
}
// Codegen HashTable::Equals
Function* equals_fn = _hash_tbl->codegen_equals(state);
if (equals_fn == NULL) {
return NULL;
}
// Codegen for evaluating build rows
Function* eval_build_row_fn = _hash_tbl->codegen_eval_tuple_row(state, true);
if (eval_build_row_fn == NULL) {
return NULL;
}
// Codegen for evaluating probe rows
Function* eval_probe_row_fn = _hash_tbl->codegen_eval_tuple_row(state, false);
if (eval_probe_row_fn == NULL) {
return NULL;
}
// Replace call sites
process_batch_fn = codegen->replace_call_sites(
process_batch_fn, false, eval_build_row_fn, "eval_build_row", &replaced);
DCHECK_EQ(replaced, 1);
process_batch_fn = codegen->replace_call_sites(
process_batch_fn, false, eval_probe_row_fn, "eval_probe_row", &replaced);
DCHECK_EQ(replaced, 1);
process_batch_fn = codegen->replace_call_sites(
process_batch_fn, false, hash_fn, "hash_current_row", &replaced);
DCHECK_EQ(replaced, 2);
process_batch_fn = codegen->replace_call_sites(
process_batch_fn, false, equals_fn, "equals", &replaced);
DCHECK_EQ(replaced, 1);
}
process_batch_fn = codegen->replace_call_sites(
process_batch_fn, false, update_tuple_fn, "update_tuple", &replaced);
DCHECK_EQ(replaced, 1) << "One call site should be replaced.";
DCHECK(process_batch_fn != NULL);
return codegen->optimize_function_with_exprs(process_batch_fn);
}
}