in be/src/exec/filter-context.cc [372:590]
Status FilterContext::CodegenInsert(LlvmCodeGen* codegen, ScalarExpr* filter_expr,
const TRuntimeFilterDesc& filter_desc, llvm::Function** fn) {
llvm::LLVMContext& context = codegen->context();
LlvmBuilder builder(context);
*fn = nullptr;
llvm::PointerType* this_type = codegen->GetStructPtrType<FilterContext>();
llvm::PointerType* tuple_row_ptr_type = codegen->GetStructPtrType<TupleRow>();
LlvmCodeGen::FnPrototype prototype(
codegen, "FilterContextInsert", codegen->void_type());
prototype.AddArgument(LlvmCodeGen::NamedVariable("this", this_type));
prototype.AddArgument(LlvmCodeGen::NamedVariable("row", tuple_row_ptr_type));
llvm::Value* args[2];
llvm::Function* insert_filter_fn = prototype.GeneratePrototype(&builder, args);
llvm::Value* this_arg = args[0];
llvm::Value* row_arg = args[1];
llvm::Value* local_filter_arg;
// The function for inserting into the in-list filter.
llvm::Function* insert_in_list_filter_fn = nullptr;
if (filter_desc.type == TRuntimeFilterType::BLOOM) {
// Load 'local_bloom_filter' from 'this_arg' FilterContext object.
llvm::Value* local_bloom_filter_ptr =
builder.CreateStructGEP(nullptr, this_arg, 3, "local_bloom_filter_ptr");
local_filter_arg =
builder.CreateLoad(local_bloom_filter_ptr, "local_bloom_filter_arg");
} else if (filter_desc.type == TRuntimeFilterType::MIN_MAX) {
// Load 'local_min_max_filter' from 'this_arg' FilterContext object.
llvm::Value* local_min_max_filter_ptr =
builder.CreateStructGEP(nullptr, this_arg, 4, "local_min_max_filter_ptr");
llvm::PointerType* min_max_filter_type =
codegen->GetNamedPtrType(MinMaxFilter::GetLlvmClassName(
filter_expr->type().type))->getPointerTo();
local_min_max_filter_ptr = builder.CreatePointerCast(
local_min_max_filter_ptr, min_max_filter_type, "cast_min_max_filter_ptr");
local_filter_arg =
builder.CreateLoad(local_min_max_filter_ptr, "local_min_max_filter_arg");
} else {
DCHECK(filter_desc.type == TRuntimeFilterType::IN_LIST);
// Load 'local_in_list_filter' from 'this_arg' FilterContext object.
llvm::Value* local_in_list_filter_ptr =
builder.CreateStructGEP(nullptr, this_arg, 5, "local_in_list_filter_ptr");
switch (filter_expr->type().type) {
case TYPE_TINYINT:
insert_in_list_filter_fn = codegen->GetFunction(
IRFunction::TINYINT_IN_LIST_FILTER_INSERT, false);
break;
case TYPE_SMALLINT:
insert_in_list_filter_fn = codegen->GetFunction(
IRFunction::SMALLINT_IN_LIST_FILTER_INSERT, false);
break;
case TYPE_INT:
insert_in_list_filter_fn = codegen->GetFunction(
IRFunction::INT_IN_LIST_FILTER_INSERT, false);
break;
case TYPE_BIGINT:
insert_in_list_filter_fn = codegen->GetFunction(
IRFunction::BIGINT_IN_LIST_FILTER_INSERT, false);
break;
case TYPE_DATE:
insert_in_list_filter_fn = codegen->GetFunction(
IRFunction::DATE_IN_LIST_FILTER_INSERT, false);
break;
case TYPE_STRING:
insert_in_list_filter_fn = codegen->GetFunction(
IRFunction::STRING_IN_LIST_FILTER_INSERT, false);
break;
case TYPE_CHAR:
insert_in_list_filter_fn = codegen->GetFunction(
IRFunction::CHAR_IN_LIST_FILTER_INSERT, false);
break;
case TYPE_VARCHAR:
insert_in_list_filter_fn = codegen->GetFunction(
IRFunction::VARCHAR_IN_LIST_FILTER_INSERT, false);
break;
default:
DCHECK(false);
break;
}
// Get type of the InListFilterImpl class from the first arg of the Insert() method.
// We can't hardcode the class name since it's a template class. The class name will
// be something like "class.impala::InListFilterImpl.1408". The last number is a
// unique id appended by LLVM at runtime.
llvm::Type* filter_impl_type = insert_in_list_filter_fn->arg_begin()->getType();
llvm::PointerType* in_list_filter_type = codegen->GetPtrType(filter_impl_type);
local_in_list_filter_ptr = builder.CreatePointerCast(
local_in_list_filter_ptr, in_list_filter_type, "cast_in_list_filter_ptr");
local_filter_arg =
builder.CreateLoad(local_in_list_filter_ptr, "local_in_list_filter_arg");
}
// Check if 'local_bloom_filter', 'local_min_max_filter' or 'local_in_list_filter' are
// NULL (depending on filter desc) and return if so.
llvm::Value* filter_null = builder.CreateIsNull(local_filter_arg, "filter_is_null");
llvm::BasicBlock* filter_not_null_block =
llvm::BasicBlock::Create(context, "filters_not_null", insert_filter_fn);
llvm::BasicBlock* filter_null_block =
llvm::BasicBlock::Create(context, "filters_null", insert_filter_fn);
llvm::BasicBlock* check_val_block =
llvm::BasicBlock::Create(context, "check_val_block", insert_filter_fn);
builder.CreateCondBr(filter_null, filter_null_block, filter_not_null_block);
builder.SetInsertPoint(filter_null_block);
builder.CreateRetVoid();
builder.SetInsertPoint(filter_not_null_block);
// Test whether 'local_min_max_filter->AlwaysTrue()' is true and return if so.
if (filter_desc.type == TRuntimeFilterType::MIN_MAX) {
// Get the function for boolean <Type>MinMaxFilter::AlwaysTrue().
llvm::Function* always_true_member_fn = codegen->GetFunction(
MinMaxFilter::GetAlwaysTrueIRFunctionType(filter_expr->type()), false);
DCHECK(always_true_member_fn != nullptr);
llvm::Value* always_true_result =
builder.CreateCall(always_true_member_fn, {local_filter_arg});
llvm::BasicBlock* always_true_true_block =
llvm::BasicBlock::Create(context, "always_true_true_block", insert_filter_fn);
llvm::BasicBlock* always_true_false_block =
llvm::BasicBlock::Create(context, "always_true_false_block", insert_filter_fn);
builder.CreateCondBr(
always_true_result, always_true_true_block, always_true_false_block);
builder.SetInsertPoint(always_true_true_block);
builder.CreateRetVoid();
builder.SetInsertPoint(always_true_false_block);
builder.CreateBr(check_val_block);
} else {
builder.CreateBr(check_val_block);
}
builder.SetInsertPoint(check_val_block);
llvm::Function* compute_fn;
RETURN_IF_ERROR(filter_expr->GetCodegendComputeFn(codegen, false, &compute_fn));
DCHECK(compute_fn != nullptr);
// Load 'expr_eval' from 'this_arg' FilterContext object.
llvm::Value* expr_eval_ptr =
builder.CreateStructGEP(nullptr, this_arg, 0, "expr_eval_ptr");
llvm::Value* expr_eval_arg = builder.CreateLoad(expr_eval_ptr, "expr_eval_arg");
// Evaluate the row against the filter's expression.
llvm::Value* compute_fn_args[] = {expr_eval_arg, row_arg};
CodegenAnyVal result = CodegenAnyVal::CreateCallWrapped(
codegen, &builder, filter_expr->type(), compute_fn, compute_fn_args, "result");
CodegenAnyValReadWriteInfo rwi = result.ToReadWriteInfo();
rwi.entry_block().BranchTo(&builder);
llvm::BasicBlock* insert_filter_block =
llvm::BasicBlock::Create(context, "insert_filter", insert_filter_fn);
// Set the pointer to NULL in case it evaluates to NULL.
builder.SetInsertPoint(rwi.null_block());
llvm::Value* null_ptr = codegen->null_ptr_value();
builder.CreateBr(insert_filter_block);
// Saves 'result' on the stack and passes a pointer to it to Insert().
builder.SetInsertPoint(rwi.non_null_block());
llvm::Value* native_ptr = SlotDescriptor::CodegenStoreNonNullAnyValToNewAlloca(rwi);
native_ptr = builder.CreatePointerCast(native_ptr, codegen->ptr_type(), "native_ptr");
builder.CreateBr(insert_filter_block);
// Get the arguments in place to call Insert().
builder.SetInsertPoint(insert_filter_block);
llvm::PHINode* val_ptr_phi = rwi.CodegenNullPhiNode(native_ptr, null_ptr,
"val_ptr_phi");
// Insert into the bloom filter.
if (filter_desc.type == TRuntimeFilterType::BLOOM) {
// Create a global constant of the filter expression's ColumnType. It needs to be a
// constant for constant propagation and dead code elimination in 'get_hash_value_fn'.
llvm::Type* col_type = codegen->GetStructType<ColumnType>();
llvm::Constant* expr_type_arg = codegen->ConstantToGVPtr(
col_type, filter_expr->type().ToIR(codegen), "expr_type_arg");
// Call RawValue::GetHashValue() on the result of the filter's expression.
llvm::Value* seed_arg =
codegen->GetI32Constant(RuntimeFilterBank::DefaultHashSeed());
llvm::Value* get_hash_value_args[] = {val_ptr_phi, expr_type_arg, seed_arg};
llvm::Function* get_hash_value_fn =
codegen->GetFunction(IRFunction::RAW_VALUE_GET_HASH_VALUE_FAST_HASH32, false);
DCHECK(get_hash_value_fn != nullptr);
llvm::Value* hash_value =
builder.CreateCall(get_hash_value_fn, get_hash_value_args, "hash_value");
// Call Insert() on the bloom filter.
llvm::Function* insert_bloom_filter_fn =
codegen->GetFunction(IRFunction::BLOOM_FILTER_INSERT, false);
DCHECK(insert_bloom_filter_fn != nullptr);
llvm::Value* insert_args[] = {local_filter_arg, hash_value};
builder.CreateCall(insert_bloom_filter_fn, insert_args);
} else if (filter_desc.type == TRuntimeFilterType::MIN_MAX) {
// The function for inserting into the min-max filter.
llvm::Function* min_max_insert_fn = codegen->GetFunction(
MinMaxFilter::GetInsertIRFunctionType(filter_expr->type()), false);
DCHECK(min_max_insert_fn != nullptr);
llvm::Value* insert_filter_args[] = {local_filter_arg, val_ptr_phi};
builder.CreateCall(min_max_insert_fn, insert_filter_args);
} else {
DCHECK(filter_desc.type == TRuntimeFilterType::IN_LIST);
DCHECK(insert_in_list_filter_fn != nullptr);
llvm::Value* insert_filter_args[] = {local_filter_arg, val_ptr_phi};
builder.CreateCall(insert_in_list_filter_fn, insert_filter_args);
}
builder.CreateRetVoid();
*fn = codegen->FinalizeFunction(insert_filter_fn);
if (*fn == nullptr) {
return Status("Codegen'ed FilterContext::Insert() fails verification, see log");
}
return Status::OK();
}