19 #include <llvm/IR/InstIterator.h>
20 #include <llvm/IR/Verifier.h>
21 #include <llvm/Support/raw_os_ostream.h>
22 #include <llvm/Transforms/Utils/BasicBlockUtils.h>
24 #include <boost/algorithm/string.hpp>
33 const auto pi8_type = llvm::PointerType::get(
get_int_type(8, ctx), 0);
34 const auto ppi8_type = llvm::PointerType::get(pi8_type, 0);
35 const auto pi64_type = llvm::PointerType::get(
get_int_type(64, ctx), 0);
36 const auto ppi64_type = llvm::PointerType::get(pi64_type, 0);
39 const auto func_type = llvm::FunctionType::get(
41 {pi8_type, ppi8_type, pi64_type, ppi8_type, ppi64_type, ppi8_type, pi64_type},
44 auto func = llvm::Function::Create(func_type,
45 llvm::Function::ExternalLinkage,
46 "call_table_function",
48 auto arg_it = func->arg_begin();
49 const auto mgr_arg = &*arg_it;
50 mgr_arg->setName(
"mgr_ptr");
51 const auto input_cols_arg = &*(++arg_it);
52 input_cols_arg->setName(
"input_col_buffers");
53 const auto input_row_counts = &*(++arg_it);
54 input_row_counts->setName(
"input_row_counts");
55 const auto input_str_dict_proxies = &*(++arg_it);
56 input_str_dict_proxies->setName(
"input_str_dict_proxies");
57 const auto output_buffers = &*(++arg_it);
58 output_buffers->setName(
"output_buffers");
59 const auto output_str_dict_proxies = &*(++arg_it);
60 output_str_dict_proxies->setName(
"output_str_dict_proxies");
61 const auto output_row_count = &*(++arg_it);
62 output_row_count->setName(
"output_row_count");
67 llvm::LLVMContext& ctx) {
68 if (elem_ti.
is_fp()) {
85 LOG(
FATAL) <<
"get_llvm_type_from_sql_column_type: not implemented for "
92 llvm::Value* value_ptr,
93 llvm::IRBuilder<>& ir_builder) {
94 if (value_ptr !=
nullptr) {
95 if (value_ptr->getType() == member_llvm_type->getPointerElementType()) {
96 ir_builder.CreateStore(value_ptr, member_ptr);
98 auto tmp = ir_builder.CreateBitCast(value_ptr, member_llvm_type);
99 ir_builder.CreateStore(tmp, member_ptr);
102 ir_builder.CreateStore(llvm::Constant::getNullValue(member_llvm_type), member_ptr);
106 template <
typename T>
109 int64_t default_value,
110 llvm::LLVMContext& ctx,
111 llvm::IRBuilder<>& ir_builder) {
112 llvm::Value* val =
nullptr;
113 if (value !=
nullptr) {
114 auto value_type = value->getType();
115 if (value_type->isPointerTy()) {
116 CHECK(value_type->getPointerElementType()->isIntegerTy(
sizeof(
T) * 8));
117 val = ir_builder.CreateLoad(value->getType()->getPointerElementType(), value);
119 CHECK(value_type->isIntegerTy(
sizeof(
T) * 8));
122 ir_builder.CreateStore(val, member_ptr);
124 auto const_default = ll_int<T>(default_value, ctx);
125 ir_builder.CreateStore(const_default, member_ptr);
129 std::tuple<llvm::Value*, llvm::Value*>
alloc_column(std::string col_name,
132 llvm::Value* data_ptr,
133 llvm::Value* data_size,
134 llvm::Value* data_str_dict_proxy_ptr,
135 llvm::LLVMContext& ctx,
136 llvm::IRBuilder<>& ir_builder) {
150 const bool is_text_encoding_dict_type =
153 llvm::StructType* col_struct_type;
156 if (is_text_encoding_dict_type) {
157 col_struct_type = llvm::StructType::get(
161 llvm::Type::getInt64Ty(ctx),
162 llvm::Type::getInt8PtrTy(ctx)
166 llvm::StructType::get(ctx,
169 llvm::Type::getInt64Ty(ctx)
173 auto col = ir_builder.CreateAlloca(col_struct_type);
174 col->setName(col_name);
175 auto col_ptr_ptr = ir_builder.CreateStructGEP(col_struct_type, col, 0);
176 auto col_sz_ptr = ir_builder.CreateStructGEP(col_struct_type, col, 1);
177 auto col_str_dict_ptr = is_text_encoding_dict_type
178 ? ir_builder.CreateStructGEP(col_struct_type, col, 2)
180 col_ptr_ptr->setName(col_name +
".ptr");
181 col_sz_ptr->setName(col_name +
".sz");
182 if (is_text_encoding_dict_type) {
183 col_str_dict_ptr->setName(col_name +
".string_dict_proxy");
187 initialize_int_member<int64_t>(col_sz_ptr, data_size, -1, ctx, ir_builder);
188 if (is_text_encoding_dict_type) {
190 llvm::Type::getInt8PtrTy(ctx),
191 data_str_dict_proxy_ptr,
194 auto col_ptr = ir_builder.CreatePointerCast(
195 col_ptr_ptr, llvm::PointerType::get(llvm::Type::getInt8Ty(ctx), 0));
196 col_ptr->setName(col_name +
"_ptr");
197 return {col, col_ptr};
202 llvm::Value* data_ptrs,
204 llvm::Value* data_size,
205 llvm::Value* data_str_dict_proxy_ptrs,
206 llvm::LLVMContext& ctx,
207 llvm::IRBuilder<>& ir_builder) {
214 llvm::Type* data_ptrs_llvm_type = llvm::Type::getInt8PtrTy(ctx);
215 const bool is_text_encoding_dict_type =
219 llvm::StructType* col_list_struct_type =
220 is_text_encoding_dict_type
221 ? llvm::StructType::get(
225 llvm::Type::getInt64Ty(ctx),
226 llvm::Type::getInt64Ty(ctx),
229 : llvm::StructType::get(ctx,
232 llvm::Type::getInt64Ty(ctx),
233 llvm::Type::getInt64Ty(ctx)
236 auto col_list = ir_builder.CreateAlloca(col_list_struct_type);
237 col_list->setName(col_list_name);
238 auto col_list_ptr_ptr = ir_builder.CreateStructGEP(col_list_struct_type, col_list, 0);
239 auto col_list_length_ptr =
240 ir_builder.CreateStructGEP(col_list_struct_type, col_list, 1);
241 auto col_list_size_ptr = ir_builder.CreateStructGEP(col_list_struct_type, col_list, 2);
242 auto col_str_dict_ptr_ptr =
243 is_text_encoding_dict_type
244 ? ir_builder.CreateStructGEP(col_list_struct_type, col_list, 3)
247 col_list_ptr_ptr->setName(col_list_name +
".ptrs");
248 col_list_length_ptr->setName(col_list_name +
".length");
249 col_list_size_ptr->setName(col_list_name +
".size");
250 if (is_text_encoding_dict_type) {
251 col_str_dict_ptr_ptr->setName(col_list_name +
".string_dict_proxies");
257 auto const_length = llvm::ConstantInt::get(llvm::Type::getInt64Ty(ctx), length,
true);
258 ir_builder.CreateStore(const_length, col_list_length_ptr);
260 initialize_int_member<int64_t>(col_list_size_ptr, data_size, -1, ctx, ir_builder);
262 if (is_text_encoding_dict_type) {
264 data_str_dict_proxy_ptrs->getType(),
265 data_str_dict_proxy_ptrs,
269 auto col_list_ptr = ir_builder.CreatePointerCast(
270 col_list_ptr_ptr, llvm::PointerType::get(llvm::Type::getInt8Ty(ctx), 0));
271 col_list_ptr->setName(col_list_name +
"_ptrs");
278 llvm::Value* data_ptr,
279 llvm::Value* data_size,
280 llvm::Value* data_is_null,
281 llvm::LLVMContext& ctx,
282 llvm::IRBuilder<>& ir_builder) {
291 llvm::StructType* arr_struct_type;
295 llvm::StructType::get(ctx,
298 llvm::Type::getInt64Ty(ctx),
299 llvm::Type::getInt8Ty(ctx)
302 auto arr = ir_builder.CreateAlloca(arr_struct_type);
303 arr->setName(arr_name);
304 auto arr_ptr_ptr = ir_builder.CreateStructGEP(arr_struct_type, arr, 0);
305 auto arr_sz_ptr = ir_builder.CreateStructGEP(arr_struct_type, arr, 1);
306 auto arr_is_null_ptr = ir_builder.CreateStructGEP(arr_struct_type, arr, 2);
307 arr_ptr_ptr->setName(arr_name +
".ptr");
308 arr_sz_ptr->setName(arr_name +
".size");
309 arr_is_null_ptr->setName(arr_name +
".is_null");
312 initialize_int_member<int64_t>(arr_sz_ptr, data_size, -1, ctx, ir_builder);
313 initialize_int_member<int8_t>(arr_is_null_ptr, data_is_null, -1, ctx, ir_builder);
314 auto arr_ptr = ir_builder.CreatePointerCast(
315 arr_ptr_ptr, llvm::PointerType::get(llvm::Type::getInt8Ty(ctx), 0));
316 arr_ptr->setName(arr_name +
"_pointer");
320 std::string
exprsKey(
const std::vector<Analyzer::Expr*>& exprs) {
322 for (
const auto& expr : exprs) {
323 const auto& ti = expr->get_type_info();
324 result += ti.to_string() +
", ";
333 bool emit_only_preflight_fn) {
352 auto cgen_state =
executor_->getCgenStatePtr();
354 CHECK(cgen_state->module_ ==
nullptr);
355 cgen_state->set_module_shallow_copy(
executor_->get_rt_module());
362 CHECK(!emit_only_preflight_fn);
365 std::shared_ptr<CompilationContext> code;
367 code =
finalize(emit_only_preflight_fn);
368 }
catch (
const std::exception& e) {
382 auto mod =
executor_->get_rt_udf_module(is_gpu).get();
383 if (mod !=
nullptr) {
384 auto* flag = mod->getModuleFlag(
"pass_column_arguments_by_value");
385 if (
auto* cnt = llvm::mdconst::extract_or_null<llvm::ConstantInt>(flag)) {
386 return cnt->getZExtValue();
396 const std::vector<llvm::Value*>& func_args,
397 llvm::BasicBlock* bb_exit,
398 llvm::Value* output_row_count_ptr,
399 bool emit_only_preflight_fn) {
400 auto cgen_state =
executor_->getCgenStatePtr();
402 llvm::LLVMContext& ctx = cgen_state->context_;
403 llvm::IRBuilder<>* ir_builder = &cgen_state->ir_builder_;
405 std::string func_name =
408 llvm::Value* table_func_return =
409 cgen_state->emitExternalCall(func_name,
get_int_type(32, ctx), func_args);
411 table_func_return->setName(emit_only_preflight_fn ?
"preflight_check_func_ret"
417 llvm::BasicBlock* bb_exit_0 =
420 llvm::Constant* const_zero =
421 llvm::ConstantInt::get(table_func_return->getType(), 0,
true);
422 llvm::Value* is_ok = ir_builder->CreateICmpSGE(table_func_return, const_zero);
423 ir_builder->CreateCondBr(is_ok, bb_exit_0, bb_exit);
425 ir_builder->SetInsertPoint(bb_exit_0);
427 ir_builder->CreateIntCast(table_func_return,
get_int_type(64, ctx),
true);
428 ir_builder->CreateStore(r, output_row_count_ptr);
429 ir_builder->CreateRet(const_zero);
431 ir_builder->SetInsertPoint(bb_exit);
436 ir_builder->CreateRet(table_func_return);
441 bool emit_only_preflight_fn) {
446 const auto mgr_ptr = &*arg_it;
447 const auto input_cols_arg = &*(++arg_it);
448 const auto input_row_counts_arg = &*(++arg_it);
449 const auto input_str_dict_proxies_arg = &*(++arg_it);
450 const auto output_buffers_arg = &*(++arg_it);
451 const auto output_str_dict_proxies_arg = &*(++arg_it);
452 const auto output_row_count_ptr = &*(++arg_it);
453 auto cgen_state =
executor_->getCgenStatePtr();
455 auto& ctx = cgen_state->context_;
457 llvm::BasicBlock* bb_entry =
459 cgen_state->ir_builder_.SetInsertPoint(bb_entry);
461 llvm::BasicBlock* bb_exit = llvm::BasicBlock::Create(ctx,
".exit",
entry_point_func_);
463 llvm::BasicBlock* func_body_bb = llvm::BasicBlock::Create(
464 ctx,
".func_body0", cgen_state->ir_builder_.GetInsertBlock()->getParent());
466 cgen_state->ir_builder_.SetInsertPoint(bb_entry);
467 cgen_state->ir_builder_.CreateBr(func_body_bb);
469 cgen_state->ir_builder_.SetInsertPoint(func_body_bb);
471 exe_unit.
input_exprs.size(), input_cols_arg, cgen_state->ir_builder_, ctx);
474 exe_unit.
input_exprs.size(), input_row_counts_arg, cgen_state->ir_builder_, ctx);
476 auto input_str_dict_proxy_heads = std::vector<llvm::Value*>();
479 input_str_dict_proxies_arg,
480 cgen_state->ir_builder_,
486 std::vector<llvm::Value*> func_args;
487 size_t func_arg_index = 0;
489 func_args.push_back(mgr_ptr);
494 for (
size_t i = 0; i < exe_unit.
input_exprs.size(); i++) {
496 const auto& ti = expr->get_type_info();
497 if (col_index == -1) {
501 auto r = cgen_state->ir_builder_.CreateBitCast(
503 llvm::LoadInst* scalar_fp = cgen_state->ir_builder_.CreateLoad(
504 r->getType()->getPointerElementType(),
507 func_args.push_back(scalar_fp);
509 }
else if (ti.is_integer() || ti.is_boolean() || ti.is_timestamp() ||
510 ti.is_timeinterval()) {
511 auto r = cgen_state->ir_builder_.CreateBitCast(
513 llvm::LoadInst* scalar_int = cgen_state->ir_builder_.CreateLoad(
514 r->getType()->getPointerElementType(),
517 func_args.push_back(scalar_int);
519 }
else if (ti.is_text_encoding_none()) {
521 cgen_state->ir_builder_.CreateBitCast(col_heads[i],
get_int_ptr_type(64, ctx));
522 auto varchar_ptr = cgen_state->ir_builder_.CreateGEP(
523 col_heads[i]->getType()->getScalarType()->getPointerElementType(),
525 cgen_state->llInt(8));
526 auto [varchar_struct, varchar_struct_ptr] =
alloc_column(
527 std::string(
"input_varchar_literal.") +
std::to_string(func_arg_index),
534 cgen_state->ir_builder_);
536 (pass_column_by_value
537 ? cgen_state->ir_builder_.CreateLoad(
538 varchar_struct->getType()->getPointerElementType(), varchar_struct)
539 : varchar_struct_ptr));
541 }
else if (ti.is_column()) {
549 : input_str_dict_proxy_heads[i],
551 cgen_state->ir_builder_);
552 func_args.push_back((pass_column_by_value
553 ? cgen_state->ir_builder_.CreateLoad(
554 col->getType()->getPointerElementType(), col)
557 }
else if (ti.is_column_list()) {
558 if (col_index == -1) {
565 input_str_dict_proxy_heads[i],
567 cgen_state->ir_builder_);
568 func_args.push_back(col_list);
571 if (col_index + 1 == ti.get_dimension()) {
574 }
else if (ti.is_array()) {
588 cgen_state->ir_builder_.CreateBitCast(col_heads[i],
get_int_ptr_type(64, ctx));
589 auto array_is_null_ptr = cgen_state->ir_builder_.CreateGEP(
590 col_heads[i]->getType()->getScalarType()->getPointerElementType(),
592 cgen_state->llInt(8));
593 auto array_is_null = cgen_state->ir_builder_.CreateLoad(
594 array_is_null_ptr->getType()->getPointerElementType(), array_is_null_ptr);
596 auto array_ptr = cgen_state->ir_builder_.CreateGEP(
597 col_heads[i]->getType()->getScalarType()->getPointerElementType(),
599 cgen_state->llInt(16));
600 array_size->setName(std::string(
"array_size.") +
std::to_string(func_arg_index));
601 array_is_null->setName(std::string(
"array_is_null.") +
603 array_ptr->setName(std::string(
"array_ptr.") +
std::to_string(func_arg_index));
605 auto array_struct_ptr =
613 cgen_state->ir_builder_);
617 CHECK_EQ(pass_column_by_value,
false);
618 func_args.push_back(array_struct_ptr);
621 throw std::runtime_error(
"Table function input has unsupported type: " +
625 auto output_str_dict_proxy_heads =
628 output_str_dict_proxies_arg,
629 cgen_state->ir_builder_,
631 : std::vector<llvm::Value*>();
633 std::vector<llvm::Value*> output_col_args;
634 for (
size_t i = 0; i < exe_unit.
target_exprs.size(); i++) {
635 auto* gep = cgen_state->ir_builder_.CreateGEP(
636 output_buffers_arg->getType()->getScalarType()->getPointerElementType(),
638 cgen_state->llInt(i));
640 cgen_state->ir_builder_.CreateLoad(gep->getType()->getPointerElementType(), gep);
642 const auto& ti = expr->get_type_info();
643 CHECK(!ti.is_column());
644 CHECK(!ti.is_column_list());
647 CHECK_EQ(ti.supportsFlatBuffer(), ti.usesFlatBuffer()) << ti;
656 output_row_count_ptr,
660 cgen_state->ir_builder_);
662 cgen_state->emitExternalCall(
663 "TableFunctionManager_register_output_column",
664 llvm::Type::getVoidTy(ctx),
665 {mgr_ptr, llvm::ConstantInt::get(
get_int_type(32, ctx), i,
true), col_ptr});
667 output_col_args.push_back((pass_column_by_value ? col : col_ptr));
675 cgen_state->emitExternalCall(
676 "TableFunctionManager_set_output_row_size",
677 llvm::Type::getVoidTy(ctx),
679 cgen_state->ir_builder_.CreateLoad(
680 output_row_count_ptr->getType()->getPointerElementType(),
681 output_row_count_ptr)});
684 if (!emit_only_preflight_fn) {
685 for (
auto& col : output_col_args) {
686 func_args.push_back((pass_column_by_value
687 ? cgen_state->ir_builder_.CreateLoad(
688 col->getType()->getPointerElementType(), col)
694 exe_unit, func_args, bb_exit, output_row_count_ptr, emit_only_preflight_fn);
706 std::vector<llvm::Type*> arg_types;
710 [&arg_types](
const auto& arg) { arg_types.push_back(arg.getType()); });
713 auto cgen_state =
executor_->getCgenStatePtr();
715 auto& ctx = cgen_state->context_;
717 std::vector<llvm::Type*> wrapper_arg_types(arg_types.size() + 1);
718 wrapper_arg_types[0] = llvm::PointerType::get(
get_int_type(32, ctx), 0);
719 wrapper_arg_types[1] = arg_types[0];
721 for (
size_t i = 1; i < arg_types.size(); ++i) {
722 wrapper_arg_types[i + 1] = arg_types[i];
726 llvm::FunctionType::get(llvm::Type::getVoidTy(ctx), wrapper_arg_types,
false);
728 llvm::Function::ExternalLinkage,
730 cgen_state->module_);
732 auto wrapper_bb_entry = llvm::BasicBlock::Create(ctx,
".entry",
kernel_func_, 0);
733 llvm::IRBuilder<> b(ctx);
734 b.SetInsertPoint(wrapper_bb_entry);
735 std::vector<llvm::Value*> loaded_args = {
kernel_func_->arg_begin() + 1};
736 for (
size_t i = 2; i < wrapper_arg_types.size(); ++i) {
745 bool emit_only_preflight_fn) {
751 auto cgen_state =
executor_->getCgenStatePtr();
753 if (
executor_->has_rt_udf_module(is_gpu)) {
755 *(cgen_state->module_),
757 llvm::Linker::Flags::OverrideFromSrc);
760 LOG(
IR) << (emit_only_preflight_fn ?
"Pre Flight Function Entry Point IR\n"
761 :
"Table Function Entry Point IR\n")
763 std::shared_ptr<CompilationContext> code;
782 auto cpu_code = std::make_shared<CpuCompilationContext>(std::move(ee));
786 LOG(
IR) <<
"End of IR";
llvm::Type * get_fp_ptr_type(const int width, llvm::LLVMContext &context)
llvm::Function * kernel_func_
std::string exprsKey(const std::vector< Analyzer::Expr * > &exprs)
HOST DEVICE int get_size() const
bool is_timestamp() const
void generateEntryPoint(const TableFunctionExecutionUnit &exe_unit, bool emit_only_preflight_fn)
void initialize_ptr_member(llvm::Value *member_ptr, llvm::Type *member_llvm_type, llvm::Value *value_ptr, llvm::IRBuilder<> &ir_builder)
bool passColumnsByValue(const TableFunctionExecutionUnit &exe_unit)
std::vector< Analyzer::Expr * > input_exprs
const table_functions::TableFunction table_func
std::tuple< llvm::Value *, llvm::Value * > alloc_column(std::string col_name, const size_t index, const SQLTypeInfo &data_target_info, llvm::Value *data_ptr, llvm::Value *data_size, llvm::Value *data_str_dict_proxy_ptr, llvm::LLVMContext &ctx, llvm::IRBuilder<> &ir_builder)
llvm::Function * generate_entry_point(const CgenState *cgen_state)
std::shared_ptr< CompilationContext > finalize(bool emit_only_preflight_fn)
std::vector< std::string > CodeCacheKey
static ExecutionEngineWrapper generateNativeCPUCode(llvm::Function *func, const std::unordered_set< llvm::Function * > &live_funcs, const CompilationOptions &co)
llvm::Type * get_int_type(const int width, llvm::LLVMContext &context)
llvm::Value * alloc_column_list(std::string col_list_name, const SQLTypeInfo &data_target_info, llvm::Value *data_ptrs, int length, llvm::Value *data_size, llvm::Value *data_str_dict_proxy_ptrs, llvm::LLVMContext &ctx, llvm::IRBuilder<> &ir_builder)
llvm::Value * alloc_array(std::string arr_name, const size_t index, const SQLTypeInfo &data_target_info, llvm::Value *data_ptr, llvm::Value *data_size, llvm::Value *data_is_null, llvm::LLVMContext &ctx, llvm::IRBuilder<> &ir_builder)
bool hasOutputSizeKnownPreLaunch() const
void verify_function_ir(const llvm::Function *func)
size_t get_bit_width(const SQLTypeInfo &ti)
llvm::LLVMContext & context_
const CompilationOptions & co_
std::string getPreFlightFnName() const
bool usesFlatBuffer() const
static void link_udf_module(const std::unique_ptr< llvm::Module > &udf_module, llvm::Module &module, CgenState *cgen_state, llvm::Linker::Flags flags=llvm::Linker::Flags::None)
void generateTableFunctionCall(const TableFunctionExecutionUnit &exe_unit, const std::vector< llvm::Value * > &func_args, llvm::BasicBlock *bb_exit, llvm::Value *output_row_count_ptr, bool emit_only_preflight_fn)
std::string toString(const Executor::ExtModuleKinds &kind)
std::string getName(const bool drop_suffix=false, const bool lower=false) const
ExecutorDeviceType device_type
HOST DEVICE EncodingType get_compression() const
std::string serialize_llvm_object(const T *llvm_obj)
static std::shared_ptr< GpuCompilationContext > generateNativeGPUCode(Executor *executor, llvm::Function *func, llvm::Function *wrapper_func, const std::unordered_set< llvm::Function * > &live_funcs, const bool is_gpu_smem_used, const CompilationOptions &co, const GPUTarget &gpu_target)
bool hasPreFlightOutputSizer() const
llvm::Function * entry_point_func_
std::vector< llvm::Value * > generate_column_heads_load(const int num_columns, llvm::Value *byte_stream_arg, llvm::IRBuilder<> &ir_builder, llvm::LLVMContext &ctx)
llvm::Type * get_llvm_type_from_sql_column_type(const SQLTypeInfo elem_ti, llvm::LLVMContext &ctx)
#define DEBUG_TIMER(name)
static std::shared_ptr< QueryEngine > getInstance()
std::shared_ptr< CompilationContext > compile(const TableFunctionExecutionUnit &exe_unit, bool emit_only_preflight_fn)
std::vector< Analyzer::Expr * > target_exprs
void initialize_int_member(llvm::Value *member_ptr, llvm::Value *value, int64_t default_value, llvm::LLVMContext &ctx, llvm::IRBuilder<> &ir_builder)
bool is_text_encoding_none() const
SQLTypeInfo get_elem_type() const
llvm::Type * get_int_ptr_type(const int width, llvm::LLVMContext &context)