/* * Copyright 2017 MapD Technologies, Inc. * * Licensed 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. */ #include "Execute.h" #include "MaxwellCodegenPatch.h" // Driver methods for the IR generation. std::vector Executor::codegen(const Analyzer::Expr* expr, const bool fetch_columns, const CompilationOptions& co) { if (!expr) { return {posArg(expr)}; } auto iter_expr = dynamic_cast(expr); if (iter_expr) { #ifdef ENABLE_MULTIFRAG_JOIN if (iter_expr->get_rte_idx() > 0) { const auto offset = cgen_state_->frag_offsets_[iter_expr->get_rte_idx()]; if (offset) { return {cgen_state_->ir_builder_.CreateAdd(posArg(iter_expr), offset)}; } else { return {posArg(iter_expr)}; } } #endif return {posArg(iter_expr)}; } auto bin_oper = dynamic_cast(expr); if (bin_oper) { return {codegen(bin_oper, co)}; } auto u_oper = dynamic_cast(expr); if (u_oper) { return {codegen(u_oper, co)}; } auto col_var = dynamic_cast(expr); if (col_var) { return codegen(col_var, fetch_columns, co); } auto constant = dynamic_cast(expr); if (constant) { if (constant->get_is_null()) { const auto& ti = constant->get_type_info(); return {ti.is_fp() ? static_cast(inlineFpNull(ti)) : static_cast(inlineIntNull(ti))}; } // The dictionary encoding case should be handled by the parent expression // (cast, for now), here is too late to know the dictionary id CHECK_NE(kENCODING_DICT, constant->get_type_info().get_compression()); return {codegen(constant, constant->get_type_info().get_compression(), 0, co)}; } auto case_expr = dynamic_cast(expr); if (case_expr) { return {codegen(case_expr, co)}; } auto extract_expr = dynamic_cast(expr); if (extract_expr) { return {codegen(extract_expr, co)}; } auto datediff_expr = dynamic_cast(expr); if (datediff_expr) { return {codegen(datediff_expr, co)}; } auto datetrunc_expr = dynamic_cast(expr); if (datetrunc_expr) { return {codegen(datetrunc_expr, co)}; } auto charlength_expr = dynamic_cast(expr); if (charlength_expr) { return {codegen(charlength_expr, co)}; } auto like_expr = dynamic_cast(expr); if (like_expr) { return {codegen(like_expr, co)}; } auto regexp_expr = dynamic_cast(expr); if (regexp_expr) { return {codegen(regexp_expr, co)}; } auto likelihood_expr = dynamic_cast(expr); if (likelihood_expr) { return {codegen(likelihood_expr->get_arg(), fetch_columns, co)}; } auto in_expr = dynamic_cast(expr); if (in_expr) { return {codegen(in_expr, co)}; } auto in_integer_set_expr = dynamic_cast(expr); if (in_integer_set_expr) { return {codegen(in_integer_set_expr, co)}; } auto function_oper_with_custom_type_handling_expr = dynamic_cast(expr); if (function_oper_with_custom_type_handling_expr) { return {codegenFunctionOperWithCustomTypeHandling(function_oper_with_custom_type_handling_expr, co)}; } auto function_oper_expr = dynamic_cast(expr); if (function_oper_expr) { return {codegenFunctionOper(function_oper_expr, co)}; } #ifdef HAVE_CALCITE abort(); #else throw std::runtime_error("Invalid scalar expression"); #endif } llvm::Value* Executor::codegen(const Analyzer::BinOper* bin_oper, const CompilationOptions& co) { const auto optype = bin_oper->get_optype(); if (IS_ARITHMETIC(optype)) { return codegenArith(bin_oper, co); } if (IS_COMPARISON(optype)) { return codegenCmp(bin_oper, co); } if (IS_LOGIC(optype)) { return codegenLogical(bin_oper, co); } if (optype == kARRAY_AT) { return codegenArrayAt(bin_oper, co); } abort(); } llvm::Value* Executor::codegen(const Analyzer::UOper* u_oper, const CompilationOptions& co) { const auto optype = u_oper->get_optype(); switch (optype) { case kNOT: return codegenLogical(u_oper, co); case kCAST: return codegenCast(u_oper, co); case kUMINUS: return codegenUMinus(u_oper, co); case kISNULL: return codegenIsNull(u_oper, co); case kUNNEST: return codegenUnnest(u_oper, co); default: abort(); } } void Executor::codegenInnerScanNextRow() { if (cgen_state_->inner_scan_labels_.empty()) { cgen_state_->ir_builder_.CreateRet(ll_int(int32_t(0))); } else { CHECK_EQ(size_t(1), cgen_state_->scan_to_iterator_.size()); auto inner_it_val_and_ptr = cgen_state_->scan_to_iterator_.begin()->second; auto inner_it_inc = cgen_state_->ir_builder_.CreateAdd(inner_it_val_and_ptr.first, ll_int(int64_t(1))); cgen_state_->ir_builder_.CreateStore(inner_it_inc, inner_it_val_and_ptr.second); CHECK_EQ(size_t(1), cgen_state_->inner_scan_labels_.size()); cgen_state_->ir_builder_.CreateBr(cgen_state_->inner_scan_labels_.front()); } } Executor::GroupColLLVMValue Executor::groupByColumnCodegen(Analyzer::Expr* group_by_col, const size_t col_width, const CompilationOptions& co, const bool translate_null_val, const int64_t translated_null_val, GroupByAndAggregate::DiamondCodegen& diamond_codegen, std::stack& array_loops, const bool thread_mem_shared) { #ifdef ENABLE_KEY_COMPACTION CHECK_GE(col_width, sizeof(int32_t)); #else CHECK_EQ(col_width, sizeof(int64_t)); #endif auto group_key = codegen(group_by_col, true, co).front(); auto key_to_cache = group_key; if (dynamic_cast(group_by_col) && static_cast(group_by_col)->get_optype() == kUNNEST) { auto preheader = cgen_state_->ir_builder_.GetInsertBlock(); auto array_loop_head = llvm::BasicBlock::Create( cgen_state_->context_, "array_loop_head", cgen_state_->row_func_, preheader->getNextNode()); diamond_codegen.setFalseTarget(array_loop_head); const auto ret_ty = get_int_type(32, cgen_state_->context_); auto array_idx_ptr = cgen_state_->ir_builder_.CreateAlloca(ret_ty); CHECK(array_idx_ptr); cgen_state_->ir_builder_.CreateStore(ll_int(int32_t(0)), array_idx_ptr); const auto arr_expr = static_cast(group_by_col)->get_operand(); const auto& array_ti = arr_expr->get_type_info(); CHECK(array_ti.is_array()); const auto& elem_ti = array_ti.get_elem_type(); auto array_len = cgen_state_->emitExternalCall( "array_size", ret_ty, {group_key, posArg(arr_expr), ll_int(log2_bytes(elem_ti.get_logical_size()))}); cgen_state_->ir_builder_.CreateBr(array_loop_head); cgen_state_->ir_builder_.SetInsertPoint(array_loop_head); CHECK(array_len); auto array_idx = cgen_state_->ir_builder_.CreateLoad(array_idx_ptr); auto bound_check = cgen_state_->ir_builder_.CreateICmp(llvm::ICmpInst::ICMP_SLT, array_idx, array_len); auto array_loop_body = llvm::BasicBlock::Create(cgen_state_->context_, "array_loop_body", cgen_state_->row_func_); cgen_state_->ir_builder_.CreateCondBr( bound_check, array_loop_body, array_loops.empty() ? diamond_codegen.orig_cond_false_ : array_loops.top()); cgen_state_->ir_builder_.SetInsertPoint(array_loop_body); cgen_state_->ir_builder_.CreateStore(cgen_state_->ir_builder_.CreateAdd(array_idx, ll_int(int32_t(1))), array_idx_ptr); const auto array_at_fname = "array_at_" + numeric_type_name(elem_ti); const auto ar_ret_ty = elem_ti.is_fp() ? (elem_ti.get_type() == kDOUBLE ? llvm::Type::getDoubleTy(cgen_state_->context_) : llvm::Type::getFloatTy(cgen_state_->context_)) : get_int_type(elem_ti.get_logical_size() * 8, cgen_state_->context_); group_key = cgen_state_->emitExternalCall(array_at_fname, ar_ret_ty, {group_key, posArg(arr_expr), array_idx}); if (need_patch_unnest_double(elem_ti, isArchMaxwell(co.device_type_), thread_mem_shared)) { key_to_cache = spillDoubleElement(group_key, ar_ret_ty); } else { key_to_cache = group_key; } CHECK(array_loop_head); array_loops.push(array_loop_head); } cgen_state_->group_by_expr_cache_.push_back(key_to_cache); llvm::Value* orig_group_key{nullptr}; if (translate_null_val) { const std::string translator_func_name(col_width == sizeof(int32_t) ? "translate_null_key_i32_" : "translate_null_key_"); const auto& ti = group_by_col->get_type_info(); const auto key_type = get_int_type(ti.get_logical_size() * 8, cgen_state_->context_); orig_group_key = group_key; group_key = cgen_state_->emitCall(translator_func_name + numeric_type_name(ti), {group_key, static_cast(llvm::ConstantInt::get(key_type, inline_int_null_val(ti))), static_cast(llvm::ConstantInt::get(key_type, translated_null_val))}); } group_key = cgen_state_->ir_builder_.CreateBitCast(castToTypeIn(group_key, col_width * 8), get_int_type(col_width * 8, cgen_state_->context_)); if (orig_group_key) { orig_group_key = cgen_state_->ir_builder_.CreateBitCast(castToTypeIn(orig_group_key, col_width * 8), get_int_type(col_width * 8, cgen_state_->context_)); } return {group_key, orig_group_key}; }