OmniSciDB  f17484ade4
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
TableFunctionCompilationContext.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2022 HEAVY.AI, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
18 
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>
23 #include <algorithm>
24 #include <boost/algorithm/string.hpp>
25 
28 
29 namespace {
30 
31 llvm::Function* generate_entry_point(const CgenState* cgen_state) {
32  auto& ctx = cgen_state->context_;
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);
37  const auto i32_type = get_int_type(32, ctx);
38 
39  const auto func_type = llvm::FunctionType::get(
40  i32_type,
41  {pi8_type, ppi8_type, pi64_type, ppi8_type, ppi64_type, ppi8_type, pi64_type},
42  false);
43 
44  auto func = llvm::Function::Create(func_type,
45  llvm::Function::ExternalLinkage,
46  "call_table_function",
47  cgen_state->module_);
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");
63  return func;
64 }
65 
67  llvm::LLVMContext& ctx) {
68  if (elem_ti.is_fp()) {
69  return get_fp_ptr_type(elem_ti.get_size() * 8, ctx);
70  } else if (elem_ti.is_boolean()) {
71  return get_int_ptr_type(8, ctx);
72  } else if (elem_ti.is_integer()) {
73  return get_int_ptr_type(elem_ti.get_size() * 8, ctx);
74  } else if (elem_ti.is_string()) {
75  if (elem_ti.get_compression() == kENCODING_DICT) {
76  return get_int_ptr_type(elem_ti.get_size() * 8, ctx);
77  }
78  CHECK(elem_ti.is_text_encoding_none());
79  return get_int_ptr_type(8, ctx);
80  } else if (elem_ti.is_timestamp()) {
81  return get_int_ptr_type(elem_ti.get_size() * 8, ctx);
82  } else if (elem_ti.usesFlatBuffer()) {
83  return get_int_ptr_type(8, ctx);
84  }
85  LOG(FATAL) << "get_llvm_type_from_sql_column_type: not implemented for "
86  << ::toString(elem_ti);
87  return nullptr;
88 }
89 
90 void initialize_ptr_member(llvm::Value* member_ptr,
91  llvm::Type* member_llvm_type,
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);
97  } else {
98  auto tmp = ir_builder.CreateBitCast(value_ptr, member_llvm_type);
99  ir_builder.CreateStore(tmp, member_ptr);
100  }
101  } else {
102  ir_builder.CreateStore(llvm::Constant::getNullValue(member_llvm_type), member_ptr);
103  }
104 }
105 
106 void initialize_int64_member(llvm::Value* member_ptr,
107  llvm::Value* value,
108  int64_t default_value,
109  llvm::LLVMContext& ctx,
110  llvm::IRBuilder<>& ir_builder) {
111  llvm::Value* val = nullptr;
112  if (value != nullptr) {
113  auto value_type = value->getType();
114  if (value_type->isPointerTy()) {
115  CHECK(value_type->getPointerElementType()->isIntegerTy(64));
116  val = ir_builder.CreateLoad(value->getType()->getPointerElementType(), value);
117  } else {
118  CHECK(value_type->isIntegerTy(64));
119  val = value;
120  }
121  ir_builder.CreateStore(val, member_ptr);
122  } else {
123  auto const_default =
124  llvm::ConstantInt::get(llvm::Type::getInt64Ty(ctx), default_value, true);
125  ir_builder.CreateStore(const_default, member_ptr);
126  }
127 }
128 
129 std::tuple<llvm::Value*, llvm::Value*> alloc_column(std::string col_name,
130  const size_t index,
131  const SQLTypeInfo& data_target_info,
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) {
137  /*
138  Creates a new Column instance of given element type and initialize
139  its data ptr and sz members when specified. If data ptr or sz are
140  unspecified (have nullptr values) then the corresponding members
141  are initialized with NULL and -1, respectively.
142 
143  If we are allocating a TextEncodingDict Column type, this function
144  adds and populates a int8* pointer to a StringDictProxy object.
145 
146  Return a pair of Column allocation (caller should apply
147  builder.CreateLoad to it in order to construct a Column instance
148  as a value) and a pointer to the Column instance.
149  */
150  const bool is_text_encoding_dict_type =
151  data_target_info.is_string() &&
152  data_target_info.get_compression() == kENCODING_DICT;
153  llvm::StructType* col_struct_type;
154  llvm::Type* data_ptr_llvm_type =
155  get_llvm_type_from_sql_column_type(data_target_info, ctx);
156  if (is_text_encoding_dict_type) {
157  col_struct_type = llvm::StructType::get(
158  ctx,
159  {
160  data_ptr_llvm_type, /* T* ptr */
161  llvm::Type::getInt64Ty(ctx), /* int64_t sz */
162  llvm::Type::getInt8PtrTy(ctx) /* int8_t* string_dictionary_ptr */
163  });
164  } else {
165  col_struct_type =
166  llvm::StructType::get(ctx,
167  {
168  data_ptr_llvm_type, /* T* ptr */
169  llvm::Type::getInt64Ty(ctx) /* int64_t sz */
170  });
171  }
172 
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)
179  : nullptr;
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");
184  }
185 
186  initialize_ptr_member(col_ptr_ptr, data_ptr_llvm_type, data_ptr, ir_builder);
187  initialize_int64_member(col_sz_ptr, data_size, -1, ctx, ir_builder);
188  if (is_text_encoding_dict_type) {
189  initialize_ptr_member(col_str_dict_ptr,
190  llvm::Type::getInt8PtrTy(ctx),
191  data_str_dict_proxy_ptr,
192  ir_builder);
193  }
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};
198 }
199 
200 llvm::Value* alloc_column_list(std::string col_list_name,
201  const SQLTypeInfo& data_target_info,
202  llvm::Value* data_ptrs,
203  int length,
204  llvm::Value* data_size,
205  llvm::Value* data_str_dict_proxy_ptrs,
206  llvm::LLVMContext& ctx,
207  llvm::IRBuilder<>& ir_builder) {
208  /*
209  Creates a new ColumnList instance of given element type and initialize
210  its members. If data ptr or size are unspecified (have nullptr
211  values) then the corresponding members are initialized with NULL
212  and -1, respectively.
213  */
214  llvm::Type* data_ptrs_llvm_type = llvm::Type::getInt8PtrTy(ctx);
215  const bool is_text_encoding_dict_type =
216  data_target_info.is_string() &&
217  data_target_info.get_compression() == kENCODING_DICT;
218 
219  llvm::StructType* col_list_struct_type =
220  is_text_encoding_dict_type
221  ? llvm::StructType::get(
222  ctx,
223  {
224  data_ptrs_llvm_type, /* int8_t* ptrs */
225  llvm::Type::getInt64Ty(ctx), /* int64_t length */
226  llvm::Type::getInt64Ty(ctx), /* int64_t size */
227  data_ptrs_llvm_type /* int8_t* str_dict_proxy_ptrs */
228  })
229  : llvm::StructType::get(ctx,
230  {
231  data_ptrs_llvm_type, /* int8_t* ptrs */
232  llvm::Type::getInt64Ty(ctx), /* int64_t length */
233  llvm::Type::getInt64Ty(ctx) /* int64_t size */
234  });
235 
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)
245  : nullptr;
246 
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");
252  }
253 
254  initialize_ptr_member(col_list_ptr_ptr, data_ptrs_llvm_type, data_ptrs, ir_builder);
255 
256  CHECK(length >= 0);
257  auto const_length = llvm::ConstantInt::get(llvm::Type::getInt64Ty(ctx), length, true);
258  ir_builder.CreateStore(const_length, col_list_length_ptr);
259 
260  initialize_int64_member(col_list_size_ptr, data_size, -1, ctx, ir_builder);
261 
262  if (is_text_encoding_dict_type) {
263  initialize_ptr_member(col_str_dict_ptr_ptr,
264  data_str_dict_proxy_ptrs->getType(),
265  data_str_dict_proxy_ptrs,
266  ir_builder);
267  }
268 
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");
272  return col_list_ptr;
273 }
274 
275 std::string exprsKey(const std::vector<Analyzer::Expr*>& exprs) {
276  std::string result;
277  for (const auto& expr : exprs) {
278  const auto& ti = expr->get_type_info();
279  result += ti.to_string() + ", ";
280  }
281  return result;
282 }
283 
284 } // namespace
285 
286 std::shared_ptr<CompilationContext> TableFunctionCompilationContext::compile(
287  const TableFunctionExecutionUnit& exe_unit,
288  bool emit_only_preflight_fn) {
289  auto timer = DEBUG_TIMER(__func__);
290 
291  // Here we assume that Executor::tf_code_accessor is cleared when a
292  // UDTF implementation is changed. TODO: Ideally, the key should
293  // contain a hash of an UDTF implementation string. This could be
294  // achieved by including the hash value to the prefix of the UDTF
295  // name, for instance.
296  CodeCacheKey key{exe_unit.table_func.getName(),
297  exprsKey(exe_unit.input_exprs),
298  exprsKey(exe_unit.target_exprs),
299  std::to_string(emit_only_preflight_fn),
301 
302  auto cached_code = QueryEngine::getInstance()->tf_code_accessor->get_or_wait(key);
303  if (cached_code) {
304  return *cached_code;
305  }
306 
307  auto cgen_state = executor_->getCgenStatePtr();
308  CHECK(cgen_state);
309  CHECK(cgen_state->module_ == nullptr);
310  cgen_state->set_module_shallow_copy(executor_->get_rt_module());
311 
313 
314  generateEntryPoint(exe_unit, emit_only_preflight_fn);
315 
317  CHECK(!emit_only_preflight_fn);
319  }
320  std::shared_ptr<CompilationContext> code;
321  try {
322  code = finalize(emit_only_preflight_fn);
323  } catch (const std::exception& e) {
324  // Erase unsuccesful key and release lock from the get_or_wait(key) call above:
325  QueryEngine::getInstance()->tf_code_accessor->erase(key);
326  throw;
327  }
328  // get_or_wait added code with nullptr to cache, here we reset the
329  // cached code with the pointer to the generated code:
330  QueryEngine::getInstance()->tf_code_accessor->reset(key, code);
331  return code;
332 }
333 
335  const TableFunctionExecutionUnit& exe_unit) {
336  bool is_gpu = co_.device_type == ExecutorDeviceType::GPU;
337  auto mod = executor_->get_rt_udf_module(is_gpu).get();
338  if (mod != nullptr) {
339  auto* flag = mod->getModuleFlag("pass_column_arguments_by_value");
340  if (auto* cnt = llvm::mdconst::extract_or_null<llvm::ConstantInt>(flag)) {
341  return cnt->getZExtValue();
342  }
343  }
344 
345  // fallback to original behavior
346  return exe_unit.table_func.isRuntime();
347 }
348 
350  const TableFunctionExecutionUnit& exe_unit,
351  const std::vector<llvm::Value*>& func_args,
352  llvm::BasicBlock* bb_exit,
353  llvm::Value* output_row_count_ptr,
354  bool emit_only_preflight_fn) {
355  auto cgen_state = executor_->getCgenStatePtr();
356  // Emit llvm IR code to call the table function
357  llvm::LLVMContext& ctx = cgen_state->context_;
358  llvm::IRBuilder<>* ir_builder = &cgen_state->ir_builder_;
359 
360  std::string func_name =
361  (emit_only_preflight_fn ? exe_unit.table_func.getPreFlightFnName()
362  : exe_unit.table_func.getName(false, true));
363  llvm::Value* table_func_return =
364  cgen_state->emitExternalCall(func_name, get_int_type(32, ctx), func_args);
365 
366  table_func_return->setName(emit_only_preflight_fn ? "preflight_check_func_ret"
367  : "table_func_ret");
368 
369  // If table_func_return is non-negative then store the value in
370  // output_row_count and return zero. Otherwise, return
371  // table_func_return that negative value contains the error code.
372  llvm::BasicBlock* bb_exit_0 =
373  llvm::BasicBlock::Create(ctx, ".exit0", entry_point_func_);
374 
375  llvm::Constant* const_zero =
376  llvm::ConstantInt::get(table_func_return->getType(), 0, true);
377  llvm::Value* is_ok = ir_builder->CreateICmpSGE(table_func_return, const_zero);
378  ir_builder->CreateCondBr(is_ok, bb_exit_0, bb_exit);
379 
380  ir_builder->SetInsertPoint(bb_exit_0);
381  llvm::Value* r =
382  ir_builder->CreateIntCast(table_func_return, get_int_type(64, ctx), true);
383  ir_builder->CreateStore(r, output_row_count_ptr);
384  ir_builder->CreateRet(const_zero);
385 
386  ir_builder->SetInsertPoint(bb_exit);
387  ir_builder->CreateRet(table_func_return);
388 }
389 
391  const TableFunctionExecutionUnit& exe_unit,
392  bool emit_only_preflight_fn) {
393  auto timer = DEBUG_TIMER(__func__);
395  CHECK_EQ(entry_point_func_->arg_size(), 7);
396  auto arg_it = entry_point_func_->arg_begin();
397  const auto mgr_ptr = &*arg_it;
398  const auto input_cols_arg = &*(++arg_it);
399  const auto input_row_counts_arg = &*(++arg_it);
400  const auto input_str_dict_proxies_arg = &*(++arg_it);
401  const auto output_buffers_arg = &*(++arg_it);
402  const auto output_str_dict_proxies_arg = &*(++arg_it);
403  const auto output_row_count_ptr = &*(++arg_it);
404  auto cgen_state = executor_->getCgenStatePtr();
405  CHECK(cgen_state);
406  auto& ctx = cgen_state->context_;
407 
408  llvm::BasicBlock* bb_entry =
409  llvm::BasicBlock::Create(ctx, ".entry", entry_point_func_, 0);
410  cgen_state->ir_builder_.SetInsertPoint(bb_entry);
411 
412  llvm::BasicBlock* bb_exit = llvm::BasicBlock::Create(ctx, ".exit", entry_point_func_);
413 
414  llvm::BasicBlock* func_body_bb = llvm::BasicBlock::Create(
415  ctx, ".func_body0", cgen_state->ir_builder_.GetInsertBlock()->getParent());
416 
417  cgen_state->ir_builder_.SetInsertPoint(bb_entry);
418  cgen_state->ir_builder_.CreateBr(func_body_bb);
419 
420  cgen_state->ir_builder_.SetInsertPoint(func_body_bb);
421  auto col_heads = generate_column_heads_load(
422  exe_unit.input_exprs.size(), input_cols_arg, cgen_state->ir_builder_, ctx);
423  CHECK_EQ(exe_unit.input_exprs.size(), col_heads.size());
424  auto row_count_heads = generate_column_heads_load(
425  exe_unit.input_exprs.size(), input_row_counts_arg, cgen_state->ir_builder_, ctx);
426 
427  auto input_str_dict_proxy_heads = std::vector<llvm::Value*>();
429  input_str_dict_proxy_heads = generate_column_heads_load(exe_unit.input_exprs.size(),
430  input_str_dict_proxies_arg,
431  cgen_state->ir_builder_,
432  ctx);
433  }
434  // The column arguments of C++ UDTFs processed by clang must be
435  // passed by reference, see rbc issues 200 and 289.
436  auto pass_column_by_value = passColumnsByValue(exe_unit);
437  std::vector<llvm::Value*> func_args;
438  size_t func_arg_index = 0;
439  if (exe_unit.table_func.usesManager()) {
440  func_args.push_back(mgr_ptr);
441  func_arg_index++;
442  }
443  int col_index = -1;
444 
445  for (size_t i = 0; i < exe_unit.input_exprs.size(); i++) {
446  const auto& expr = exe_unit.input_exprs[i];
447  const auto& ti = expr->get_type_info();
448  if (col_index == -1) {
449  func_arg_index += 1;
450  }
451  if (ti.is_fp()) {
452  auto r = cgen_state->ir_builder_.CreateBitCast(
453  col_heads[i], get_fp_ptr_type(get_bit_width(ti), ctx));
454  llvm::LoadInst* scalar_fp = cgen_state->ir_builder_.CreateLoad(
455  r->getType()->getPointerElementType(),
456  r,
457  "input_scalar_fp." + std::to_string(func_arg_index));
458  func_args.push_back(scalar_fp);
459  CHECK_EQ(col_index, -1);
460  } else if (ti.is_integer() || ti.is_boolean() || ti.is_timestamp() ||
461  ti.is_timeinterval()) {
462  auto r = cgen_state->ir_builder_.CreateBitCast(
463  col_heads[i], get_int_ptr_type(get_bit_width(ti), ctx));
464  llvm::LoadInst* scalar_int = cgen_state->ir_builder_.CreateLoad(
465  r->getType()->getPointerElementType(),
466  r,
467  "input_scalar_int." + std::to_string(func_arg_index));
468  func_args.push_back(scalar_int);
469  CHECK_EQ(col_index, -1);
470  } else if (ti.is_text_encoding_none()) {
471  auto varchar_size =
472  cgen_state->ir_builder_.CreateBitCast(col_heads[i], get_int_ptr_type(64, ctx));
473  auto varchar_ptr = cgen_state->ir_builder_.CreateGEP(
474  col_heads[i]->getType()->getScalarType()->getPointerElementType(),
475  col_heads[i],
476  cgen_state->llInt(8));
477  auto [varchar_struct, varchar_struct_ptr] = alloc_column(
478  std::string("input_varchar_literal.") + std::to_string(func_arg_index),
479  i,
480  ti,
481  varchar_ptr,
482  varchar_size,
483  nullptr,
484  ctx,
485  cgen_state->ir_builder_);
486  func_args.push_back(
487  (pass_column_by_value
488  ? cgen_state->ir_builder_.CreateLoad(
489  varchar_struct->getType()->getPointerElementType(), varchar_struct)
490  : varchar_struct_ptr));
491  CHECK_EQ(col_index, -1);
492  } else if (ti.is_column()) {
493  auto [col, col_ptr] = alloc_column(
494  std::string("input_col.") + std::to_string(func_arg_index),
495  i,
496  ti.get_elem_type(),
497  col_heads[i],
498  row_count_heads[i],
500  : input_str_dict_proxy_heads[i],
501  ctx,
502  cgen_state->ir_builder_);
503  func_args.push_back((pass_column_by_value
504  ? cgen_state->ir_builder_.CreateLoad(
505  col->getType()->getPointerElementType(), col)
506  : col_ptr));
507  CHECK_EQ(col_index, -1);
508  } else if (ti.is_column_list()) {
509  if (col_index == -1) {
510  auto col_list = alloc_column_list(
511  std::string("input_col_list.") + std::to_string(func_arg_index),
512  ti.get_elem_type(),
513  col_heads[i],
514  ti.get_dimension(),
515  row_count_heads[i],
516  input_str_dict_proxy_heads[i],
517  ctx,
518  cgen_state->ir_builder_);
519  func_args.push_back(col_list);
520  }
521  col_index++;
522  if (col_index + 1 == ti.get_dimension()) {
523  col_index = -1;
524  }
525  } else {
526  throw std::runtime_error(
527  "Only integer and floating point columns or scalars are supported as inputs to "
528  "table "
529  "functions, got " +
530  ti.get_type_name());
531  }
532  }
533  auto output_str_dict_proxy_heads =
535  ? (generate_column_heads_load(exe_unit.target_exprs.size(),
536  output_str_dict_proxies_arg,
537  cgen_state->ir_builder_,
538  ctx))
539  : std::vector<llvm::Value*>();
540 
541  std::vector<llvm::Value*> output_col_args;
542  for (size_t i = 0; i < exe_unit.target_exprs.size(); i++) {
543  auto* gep = cgen_state->ir_builder_.CreateGEP(
544  output_buffers_arg->getType()->getScalarType()->getPointerElementType(),
545  output_buffers_arg,
546  cgen_state->llInt(i));
547  auto output_load =
548  cgen_state->ir_builder_.CreateLoad(gep->getType()->getPointerElementType(), gep);
549  const auto& expr = exe_unit.target_exprs[i];
550  const auto& ti = expr->get_type_info();
551  CHECK(!ti.is_column()); // UDTF output column type is its data type
552  CHECK(!ti.is_column_list()); // TODO: when UDTF outputs column_list, convert it to
553  // output columns
554  // UDTF output columns use FlatBuffer storage whenever type supports it
555  CHECK_EQ(ti.supportsFlatBuffer(), ti.usesFlatBuffer()) << ti;
556  auto [col, col_ptr] = alloc_column(
557  std::string("output_col.") + std::to_string(i),
558  i,
559  ti,
561  ? output_load
562  : nullptr), // CPU: set_output_row_size will set the output
563  // Column ptr member
564  output_row_count_ptr,
565  co_.device_type == ExecutorDeviceType::CPU ? output_str_dict_proxy_heads[i]
566  : nullptr,
567  ctx,
568  cgen_state->ir_builder_);
569  if (co_.device_type == ExecutorDeviceType::CPU && !emit_only_preflight_fn) {
570  cgen_state->emitExternalCall(
571  "TableFunctionManager_register_output_column",
572  llvm::Type::getVoidTy(ctx),
573  {mgr_ptr, llvm::ConstantInt::get(get_int_type(32, ctx), i, true), col_ptr});
574  }
575  output_col_args.push_back((pass_column_by_value ? col : col_ptr));
576  }
577 
578  // output column members must be set before loading column when
579  // column instances are passed by value
580  if ((exe_unit.table_func.hasOutputSizeKnownPreLaunch() ||
581  exe_unit.table_func.hasPreFlightOutputSizer()) &&
582  (co_.device_type == ExecutorDeviceType::CPU) && !emit_only_preflight_fn) {
583  cgen_state->emitExternalCall(
584  "TableFunctionManager_set_output_row_size",
585  llvm::Type::getVoidTy(ctx),
586  {mgr_ptr,
587  cgen_state->ir_builder_.CreateLoad(
588  output_row_count_ptr->getType()->getPointerElementType(),
589  output_row_count_ptr)});
590  }
591 
592  if (!emit_only_preflight_fn) {
593  for (auto& col : output_col_args) {
594  func_args.push_back((pass_column_by_value
595  ? cgen_state->ir_builder_.CreateLoad(
596  col->getType()->getPointerElementType(), col)
597  : col));
598  }
599  }
600 
602  exe_unit, func_args, bb_exit, output_row_count_ptr, emit_only_preflight_fn);
603 
604  // std::cout << "=================================" << std::endl;
605  // entry_point_func_->print(llvm::outs());
606  // std::cout << "=================================" << std::endl;
607 
609 }
610 
612  auto timer = DEBUG_TIMER(__func__);
614  std::vector<llvm::Type*> arg_types;
615  arg_types.reserve(entry_point_func_->arg_size());
616  std::for_each(entry_point_func_->arg_begin(),
617  entry_point_func_->arg_end(),
618  [&arg_types](const auto& arg) { arg_types.push_back(arg.getType()); });
619  CHECK_EQ(arg_types.size(), entry_point_func_->arg_size());
620 
621  auto cgen_state = executor_->getCgenStatePtr();
622  CHECK(cgen_state);
623  auto& ctx = cgen_state->context_;
624 
625  std::vector<llvm::Type*> wrapper_arg_types(arg_types.size() + 1);
626  wrapper_arg_types[0] = llvm::PointerType::get(get_int_type(32, ctx), 0);
627  wrapper_arg_types[1] = arg_types[0];
628 
629  for (size_t i = 1; i < arg_types.size(); ++i) {
630  wrapper_arg_types[i + 1] = arg_types[i];
631  }
632 
633  auto wrapper_ft =
634  llvm::FunctionType::get(llvm::Type::getVoidTy(ctx), wrapper_arg_types, false);
635  kernel_func_ = llvm::Function::Create(wrapper_ft,
636  llvm::Function::ExternalLinkage,
637  "table_func_kernel",
638  cgen_state->module_);
639 
640  auto wrapper_bb_entry = llvm::BasicBlock::Create(ctx, ".entry", kernel_func_, 0);
641  llvm::IRBuilder<> b(ctx);
642  b.SetInsertPoint(wrapper_bb_entry);
643  std::vector<llvm::Value*> loaded_args = {kernel_func_->arg_begin() + 1};
644  for (size_t i = 2; i < wrapper_arg_types.size(); ++i) {
645  loaded_args.push_back(kernel_func_->arg_begin() + i);
646  }
647  auto error_lv = b.CreateCall(entry_point_func_, loaded_args);
648  b.CreateStore(error_lv, kernel_func_->arg_begin());
649  b.CreateRetVoid();
650 }
651 
652 std::shared_ptr<CompilationContext> TableFunctionCompilationContext::finalize(
653  bool emit_only_preflight_fn) {
654  auto timer = DEBUG_TIMER(__func__);
655  /*
656  TODO 1: eliminate need for OverrideFromSrc
657  TODO 2: detect and link only the udf's that are needed
658  */
659  auto cgen_state = executor_->getCgenStatePtr();
660  auto is_gpu = co_.device_type == ExecutorDeviceType::GPU;
661  if (executor_->has_rt_udf_module(is_gpu)) {
662  CodeGenerator::link_udf_module(executor_->get_rt_udf_module(is_gpu),
663  *(cgen_state->module_),
664  cgen_state,
665  llvm::Linker::Flags::OverrideFromSrc);
666  }
667 
668  LOG(IR) << (emit_only_preflight_fn ? "Pre Flight Function Entry Point IR\n"
669  : "Table Function Entry Point IR\n")
671  std::shared_ptr<CompilationContext> code;
672  if (is_gpu) {
673  LOG(IR) << "Table Function Kernel IR\n" << serialize_llvm_object(kernel_func_);
674 
675  CHECK(executor_);
676  executor_->initializeNVPTXBackend();
677 
678  CodeGenerator::GPUTarget gpu_target{
679  executor_->nvptx_target_machine_.get(), executor_->cudaMgr(), cgen_state, false};
682  kernel_func_,
684  /*is_gpu_smem_used=*/false,
685  co_,
686  gpu_target);
687  } else {
688  auto ee =
690  auto cpu_code = std::make_shared<CpuCompilationContext>(std::move(ee));
691  cpu_code->setFunctionPointer(entry_point_func_);
692  code = cpu_code;
693  }
694  LOG(IR) << "End of IR";
695 
696  return code;
697 }
llvm::Type * get_fp_ptr_type(const int width, llvm::LLVMContext &context)
#define CHECK_EQ(x, y)
Definition: Logger.h:301
std::string exprsKey(const std::vector< Analyzer::Expr * > &exprs)
HOST DEVICE int get_size() const
Definition: sqltypes.h:403
bool is_timestamp() const
Definition: sqltypes.h:1044
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
#define LOG(tag)
Definition: Logger.h:285
bool is_fp() const
Definition: sqltypes.h:571
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
Definition: CodeCache.h:24
std::string toString(const QueryDescriptionType &type)
Definition: Types.h:64
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)
std::string to_string(char const *&&v)
llvm::Module * module_
Definition: CgenState.h:373
void verify_function_ir(const llvm::Function *func)
size_t get_bit_width(const SQLTypeInfo &ti)
llvm::LLVMContext & context_
Definition: CgenState.h:382
bool is_integer() const
Definition: sqltypes.h:565
bool usesFlatBuffer() const
Definition: sqltypes.h:1081
bool is_boolean() const
Definition: sqltypes.h:580
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 getName(const bool drop_suffix=false, const bool lower=false) const
ExecutorDeviceType device_type
HOST DEVICE EncodingType get_compression() const
Definition: sqltypes.h:399
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)
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 CHECK(condition)
Definition: Logger.h:291
#define DEBUG_TIMER(name)
Definition: Logger.h:412
void initialize_int64_member(llvm::Value *member_ptr, llvm::Value *value, int64_t default_value, llvm::LLVMContext &ctx, llvm::IRBuilder<> &ir_builder)
static std::shared_ptr< QueryEngine > getInstance()
Definition: QueryEngine.h:86
std::shared_ptr< CompilationContext > compile(const TableFunctionExecutionUnit &exe_unit, bool emit_only_preflight_fn)
std::vector< Analyzer::Expr * > target_exprs
bool is_string() const
Definition: sqltypes.h:559
bool is_text_encoding_none() const
Definition: sqltypes.h:612
llvm::Type * get_int_ptr_type(const int width, llvm::LLVMContext &context)