OmniSciDB  d2f719934e
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
TableFunctionCompilationContext Class Reference

#include <TableFunctionCompilationContext.h>

+ Collaboration diagram for TableFunctionCompilationContext:

Public Member Functions

 TableFunctionCompilationContext (Executor *executor)
 
 TableFunctionCompilationContext (const TableFunctionCompilationContext &)=delete
 
TableFunctionCompilationContextoperator= (const TableFunctionCompilationContext &)=delete
 
std::shared_ptr
< CompilationContext
compile (const TableFunctionExecutionUnit &exe_unit, const CompilationOptions &co, bool emit_only_require_check)
 

Private Member Functions

void generateEntryPoint (const TableFunctionExecutionUnit &exe_unit, bool is_gpu, bool emit_only_require_check)
 
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_require_check)
 
void generateGpuKernel ()
 
bool passColumnsByValue (const TableFunctionExecutionUnit &exe_unit, bool is_gpu)
 
std::shared_ptr
< CompilationContext
finalize (const CompilationOptions &co, bool emit_only_require_check)
 

Private Attributes

llvm::Function * entry_point_func_
 
llvm::Function * kernel_func_
 
Executorexecutor_
 

Detailed Description

Definition at line 29 of file TableFunctionCompilationContext.h.

Constructor & Destructor Documentation

TableFunctionCompilationContext::TableFunctionCompilationContext ( Executor executor)
inline

Definition at line 31 of file TableFunctionCompilationContext.h.

TableFunctionCompilationContext::TableFunctionCompilationContext ( const TableFunctionCompilationContext )
delete

Member Function Documentation

std::shared_ptr< CompilationContext > TableFunctionCompilationContext::compile ( const TableFunctionExecutionUnit exe_unit,
const CompilationOptions co,
bool  emit_only_require_check 
)

Definition at line 217 of file TableFunctionCompilationContext.cpp.

References CHECK, DEBUG_TIMER, CompilationOptions::device_type, entry_point_func_, executor_, finalize(), anonymous_namespace{TableFunctionCompilationContext.cpp}::generate_entry_point(), generateEntryPoint(), generateGpuKernel(), GPU, run_benchmark_import::result, and runtime_module_shallow_copy().

220  {
221  auto timer = DEBUG_TIMER(__func__);
222 
223  auto cgen_state = executor_->getCgenStatePtr();
224  CHECK(cgen_state);
225  std::unique_ptr<llvm::Module> module(runtime_module_shallow_copy(cgen_state));
226  cgen_state->module_ = module.get();
227 
229 
230  generateEntryPoint(exe_unit,
231  /*is_gpu=*/co.device_type == ExecutorDeviceType::GPU,
232  emit_only_require_check);
233 
235  CHECK(!emit_only_require_check);
237  }
238  auto result = finalize(co, emit_only_require_check);
239  module.release();
240  cgen_state->module_ = nullptr;
241  return result;
242 }
std::unique_ptr< llvm::Module > runtime_module_shallow_copy(CgenState *cgen_state)
llvm::Function * generate_entry_point(const CgenState *cgen_state)
std::shared_ptr< CompilationContext > finalize(const CompilationOptions &co, bool emit_only_require_check)
ExecutorDeviceType device_type
void generateEntryPoint(const TableFunctionExecutionUnit &exe_unit, bool is_gpu, bool emit_only_require_check)
#define CHECK(condition)
Definition: Logger.h:211
#define DEBUG_TIMER(name)
Definition: Logger.h:358

+ Here is the call graph for this function:

std::shared_ptr< CompilationContext > TableFunctionCompilationContext::finalize ( const CompilationOptions co,
bool  emit_only_require_check 
)
private

Definition at line 504 of file TableFunctionCompilationContext.cpp.

References CHECK, CPU, CompilationOptions::device_type, entry_point_func_, executor_, CodeGenerator::generateNativeCPUCode(), CodeGenerator::generateNativeGPUCode(), GPU, logger::IR, kernel_func_, CodeGenerator::link_udf_module(), LOG, rt_udf_cpu_module, rt_udf_gpu_module, and serialize_llvm_object().

Referenced by compile().

506  {
507  /*
508  TODO 1: eliminate need for OverrideFromSrc
509  TODO 2: detect and link only the udf's that are needed
510  */
511  auto cgen_state = executor_->getCgenStatePtr();
512  if (co.device_type == ExecutorDeviceType::GPU && rt_udf_gpu_module != nullptr) {
514  *(cgen_state->module_),
515  cgen_state,
516  llvm::Linker::Flags::OverrideFromSrc);
517  }
518  if (co.device_type == ExecutorDeviceType::CPU && rt_udf_cpu_module != nullptr) {
520  *(cgen_state->module_),
521  cgen_state,
522  llvm::Linker::Flags::OverrideFromSrc);
523  }
524 
525  // Add code to cache?
526 
527  LOG(IR) << (emit_only_require_check ? "Require Check Function Entry Point IR\n"
528  : "Table Function Entry Point IR\n")
530  std::shared_ptr<CompilationContext> code;
532  LOG(IR) << "Table Function Kernel IR\n" << serialize_llvm_object(kernel_func_);
533 
534  CHECK(executor_);
535  executor_->initializeNVPTXBackend();
536 
537  CodeGenerator::GPUTarget gpu_target{executor_->nvptx_target_machine_.get(),
538  executor_->cudaMgr(),
539  executor_->blockSize(),
540  cgen_state,
541  false};
543  kernel_func_,
545  /*is_gpu_smem_used=*/false,
546  co,
547  gpu_target);
548  } else {
549  auto ee =
551  auto cpu_code = std::make_shared<CpuCompilationContext>(std::move(ee));
552  cpu_code->setFunctionPointer(entry_point_func_);
553  code = cpu_code;
554  }
555  LOG(IR) << "End of IR";
556 
557  return code;
558 }
std::unique_ptr< llvm::Module > rt_udf_cpu_module
#define LOG(tag)
Definition: Logger.h:205
std::unique_ptr< llvm::Module > rt_udf_gpu_module
static ExecutionEngineWrapper generateNativeCPUCode(llvm::Function *func, const std::unordered_set< llvm::Function * > &live_funcs, const CompilationOptions &co)
static std::shared_ptr< GpuCompilationContext > generateNativeGPUCode(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)
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)
ExecutorDeviceType device_type
std::string serialize_llvm_object(const T *llvm_obj)
#define CHECK(condition)
Definition: Logger.h:211

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void TableFunctionCompilationContext::generateEntryPoint ( const TableFunctionExecutionUnit exe_unit,
bool  is_gpu,
bool  emit_only_require_check 
)
private

Definition at line 300 of file TableFunctionCompilationContext.cpp.

References anonymous_namespace{TableFunctionCompilationContext.cpp}::alloc_column(), anonymous_namespace{TableFunctionCompilationContext.cpp}::alloc_column_list(), CHECK, CHECK_EQ, entry_point_func_, executor_, generate_column_heads_load(), generateTableFunctionCall(), get_bit_width(), get_fp_ptr_type(), get_int_ptr_type(), get_int_type(), table_functions::TableFunction::hasOutputSizeKnownPreLaunch(), i, TableFunctionExecutionUnit::input_exprs, passColumnsByValue(), TableFunctionExecutionUnit::table_func, TableFunctionExecutionUnit::target_exprs, to_string(), table_functions::TableFunction::usesManager(), and verify_function_ir().

Referenced by compile().

303  {
305  CHECK_EQ(entry_point_func_->arg_size(), 5);
306  auto arg_it = entry_point_func_->arg_begin();
307  const auto mgr_ptr = &*arg_it;
308  const auto input_cols_arg = &*(++arg_it);
309  const auto input_row_counts_arg = &*(++arg_it);
310  const auto output_buffers_arg = &*(++arg_it);
311  const auto output_row_count_ptr = &*(++arg_it);
312  auto cgen_state = executor_->getCgenStatePtr();
313  CHECK(cgen_state);
314  auto& ctx = cgen_state->context_;
315 
316  llvm::BasicBlock* bb_entry =
317  llvm::BasicBlock::Create(ctx, ".entry", entry_point_func_, 0);
318  cgen_state->ir_builder_.SetInsertPoint(bb_entry);
319 
320  llvm::BasicBlock* bb_exit = llvm::BasicBlock::Create(ctx, ".exit", entry_point_func_);
321 
322  llvm::BasicBlock* func_body_bb = llvm::BasicBlock::Create(
323  ctx, ".func_body0", cgen_state->ir_builder_.GetInsertBlock()->getParent());
324 
325  cgen_state->ir_builder_.SetInsertPoint(bb_entry);
326  cgen_state->ir_builder_.CreateBr(func_body_bb);
327 
328  cgen_state->ir_builder_.SetInsertPoint(func_body_bb);
329  auto col_heads = generate_column_heads_load(
330  exe_unit.input_exprs.size(), input_cols_arg, cgen_state->ir_builder_, ctx);
331  CHECK_EQ(exe_unit.input_exprs.size(), col_heads.size());
332  auto row_count_heads = generate_column_heads_load(
333  exe_unit.input_exprs.size(), input_row_counts_arg, cgen_state->ir_builder_, ctx);
334  // The column arguments of C++ UDTFs processed by clang must be
335  // passed by reference, see rbc issues 200 and 289.
336  auto pass_column_by_value = passColumnsByValue(exe_unit, is_gpu);
337  std::vector<llvm::Value*> func_args;
338  size_t func_arg_index = 0;
339  if (exe_unit.table_func.usesManager()) {
340  func_args.push_back(mgr_ptr);
341  func_arg_index++;
342  }
343  int col_index = -1;
344  for (size_t i = 0; i < exe_unit.input_exprs.size(); i++) {
345  const auto& expr = exe_unit.input_exprs[i];
346  const auto& ti = expr->get_type_info();
347  if (col_index == -1) {
348  func_arg_index += 1;
349  }
350  if (ti.is_fp()) {
351  auto r = cgen_state->ir_builder_.CreateBitCast(
352  col_heads[i], get_fp_ptr_type(get_bit_width(ti), ctx));
353  func_args.push_back(cgen_state->ir_builder_.CreateLoad(r));
354  CHECK_EQ(col_index, -1);
355  } else if (ti.is_integer() || ti.is_boolean()) {
356  auto r = cgen_state->ir_builder_.CreateBitCast(
357  col_heads[i], get_int_ptr_type(get_bit_width(ti), ctx));
358  func_args.push_back(cgen_state->ir_builder_.CreateLoad(r));
359  CHECK_EQ(col_index, -1);
360  } else if (ti.is_bytes()) {
361  auto varchar_size =
362  cgen_state->ir_builder_.CreateBitCast(col_heads[i], get_int_ptr_type(64, ctx));
363  auto varchar_ptr =
364  cgen_state->ir_builder_.CreateGEP(col_heads[i], cgen_state->llInt(8));
365  auto [varchar_struct, varchar_struct_ptr] =
366  alloc_column(std::string("varchar_literal.") + std::to_string(func_arg_index),
367  i,
368  ti,
369  varchar_ptr,
370  varchar_size,
371  ctx,
372  cgen_state->ir_builder_);
373  func_args.push_back((pass_column_by_value
374  ? cgen_state->ir_builder_.CreateLoad(varchar_struct)
375  : varchar_struct_ptr));
376  CHECK_EQ(col_index, -1);
377  } else if (ti.is_column()) {
378  auto [col, col_ptr] =
379  alloc_column(std::string("input_col.") + std::to_string(func_arg_index),
380  i,
381  ti.get_elem_type(),
382  col_heads[i],
383  row_count_heads[i],
384  ctx,
385  cgen_state->ir_builder_);
386  func_args.push_back(
387  (pass_column_by_value ? cgen_state->ir_builder_.CreateLoad(col) : col_ptr));
388  CHECK_EQ(col_index, -1);
389  } else if (ti.is_column_list()) {
390  if (col_index == -1) {
391  auto col_list = alloc_column_list(
392  std::string("input_col_list.") + std::to_string(func_arg_index),
393  ti.get_elem_type(),
394  col_heads[i],
395  ti.get_dimension(),
396  row_count_heads[i],
397  ctx,
398  cgen_state->ir_builder_);
399  func_args.push_back(col_list);
400  }
401  col_index++;
402  if (col_index + 1 == ti.get_dimension()) {
403  col_index = -1;
404  }
405  } else {
406  throw std::runtime_error(
407  "Only integer and floating point columns or scalars are supported as inputs to "
408  "table "
409  "functions, got " +
410  ti.get_type_name());
411  }
412  }
413  std::vector<llvm::Value*> output_col_args;
414  for (size_t i = 0; i < exe_unit.target_exprs.size(); i++) {
415  auto output_load = cgen_state->ir_builder_.CreateLoad(
416  cgen_state->ir_builder_.CreateGEP(output_buffers_arg, cgen_state->llInt(i)));
417  const auto& expr = exe_unit.target_exprs[i];
418  const auto& ti = expr->get_type_info();
419  CHECK(!ti.is_column()); // UDTF output column type is its data type
420  CHECK(!ti.is_column_list()); // TODO: when UDTF outputs column_list, convert it to
421  // output columns
422  auto [col, col_ptr] = alloc_column(
423  std::string("output_col.") + std::to_string(i),
424  i,
425  ti,
426  (is_gpu ? output_load : nullptr), // CPU: set_output_row_size will set the output
427  // Column ptr member
428  output_row_count_ptr,
429  ctx,
430  cgen_state->ir_builder_);
431  if (!is_gpu) {
432  cgen_state->emitExternalCall(
433  "TableFunctionManager_register_output_column",
434  llvm::Type::getVoidTy(ctx),
435  {mgr_ptr, llvm::ConstantInt::get(get_int_type(32, ctx), i, true), col_ptr});
436  }
437  output_col_args.push_back((pass_column_by_value ? col : col_ptr));
438  }
439 
440  // output column members must be set before loading column when
441  // column instances are passed by value
442  if (exe_unit.table_func.hasOutputSizeKnownPreLaunch() && !is_gpu) {
443  cgen_state->emitExternalCall(
444  "TableFunctionManager_set_output_row_size",
445  llvm::Type::getVoidTy(ctx),
446  {mgr_ptr, cgen_state->ir_builder_.CreateLoad(output_row_count_ptr)});
447  }
448 
449  for (auto& col : output_col_args) {
450  func_args.push_back(
451  (pass_column_by_value ? cgen_state->ir_builder_.CreateLoad(col) : col));
452  }
453 
455  exe_unit, func_args, bb_exit, output_row_count_ptr, emit_only_require_check);
456 
457  // std::cout << "=================================" << std::endl;
458  // entry_point_func_->print(llvm::outs());
459  // std::cout << "=================================" << std::endl;
460 
462 }
llvm::Type * get_fp_ptr_type(const int width, llvm::LLVMContext &context)
#define CHECK_EQ(x, y)
Definition: Logger.h:219
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::LLVMContext &ctx, llvm::IRBuilder<> &ir_builder)
std::vector< Analyzer::Expr * > input_exprs
const table_functions::TableFunction table_func
llvm::Type * get_int_type(const int width, llvm::LLVMContext &context)
std::string to_string(char const *&&v)
void verify_function_ir(const llvm::Function *func)
size_t get_bit_width(const SQLTypeInfo &ti)
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::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::LLVMContext &ctx, llvm::IRBuilder<> &ir_builder)
#define CHECK(condition)
Definition: Logger.h:211
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_require_check)
bool passColumnsByValue(const TableFunctionExecutionUnit &exe_unit, bool is_gpu)
std::vector< Analyzer::Expr * > target_exprs
llvm::Type * get_int_ptr_type(const int width, llvm::LLVMContext &context)

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void TableFunctionCompilationContext::generateGpuKernel ( )
private

Definition at line 464 of file TableFunctionCompilationContext.cpp.

References CHECK, CHECK_EQ, entry_point_func_, executor_, get_int_type(), i, and kernel_func_.

Referenced by compile().

464  {
466  std::vector<llvm::Type*> arg_types;
467  arg_types.reserve(entry_point_func_->arg_size());
468  std::for_each(entry_point_func_->arg_begin(),
469  entry_point_func_->arg_end(),
470  [&arg_types](const auto& arg) { arg_types.push_back(arg.getType()); });
471  CHECK_EQ(arg_types.size(), entry_point_func_->arg_size());
472 
473  auto cgen_state = executor_->getCgenStatePtr();
474  CHECK(cgen_state);
475  auto& ctx = cgen_state->context_;
476 
477  std::vector<llvm::Type*> wrapper_arg_types(arg_types.size() + 1);
478  wrapper_arg_types[0] = llvm::PointerType::get(get_int_type(32, ctx), 0);
479  wrapper_arg_types[1] = arg_types[0];
480 
481  for (size_t i = 1; i < arg_types.size(); ++i) {
482  wrapper_arg_types[i + 1] = arg_types[i];
483  }
484 
485  auto wrapper_ft =
486  llvm::FunctionType::get(llvm::Type::getVoidTy(ctx), wrapper_arg_types, false);
487  kernel_func_ = llvm::Function::Create(wrapper_ft,
488  llvm::Function::ExternalLinkage,
489  "table_func_kernel",
490  cgen_state->module_);
491 
492  auto wrapper_bb_entry = llvm::BasicBlock::Create(ctx, ".entry", kernel_func_, 0);
493  llvm::IRBuilder<> b(ctx);
494  b.SetInsertPoint(wrapper_bb_entry);
495  std::vector<llvm::Value*> loaded_args = {kernel_func_->arg_begin() + 1};
496  for (size_t i = 2; i < wrapper_arg_types.size(); ++i) {
497  loaded_args.push_back(kernel_func_->arg_begin() + i);
498  }
499  auto error_lv = b.CreateCall(entry_point_func_, loaded_args);
500  b.CreateStore(error_lv, kernel_func_->arg_begin());
501  b.CreateRetVoid();
502 }
#define CHECK_EQ(x, y)
Definition: Logger.h:219
llvm::Type * get_int_type(const int width, llvm::LLVMContext &context)
#define CHECK(condition)
Definition: Logger.h:211

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void TableFunctionCompilationContext::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_require_check 
)
private

Definition at line 259 of file TableFunctionCompilationContext.cpp.

References entry_point_func_, executor_, get_int_type(), table_functions::TableFunction::getName(), table_functions::TableFunction::getRequireCheckFnName(), and TableFunctionExecutionUnit::table_func.

Referenced by generateEntryPoint().

264  {
265  auto cgen_state = executor_->getCgenStatePtr();
266  // Emit llvm IR code to call the table function
267  llvm::LLVMContext& ctx = cgen_state->context_;
268  llvm::IRBuilder<>* ir_builder = &cgen_state->ir_builder_;
269 
270  std::string func_name =
271  (emit_only_require_check ? exe_unit.table_func.getRequireCheckFnName()
272  : exe_unit.table_func.getName(false, true));
273  llvm::Value* table_func_return =
274  cgen_state->emitExternalCall(func_name, get_int_type(32, ctx), func_args);
275 
276  table_func_return->setName(emit_only_require_check ? "require_check_func_ret"
277  : "table_func_ret");
278 
279  // If table_func_return is non-negative then store the value in
280  // output_row_count and return zero. Otherwise, return
281  // table_func_return that negative value contains the error code.
282  llvm::BasicBlock* bb_exit_0 =
283  llvm::BasicBlock::Create(ctx, ".exit0", entry_point_func_);
284 
285  llvm::Constant* const_zero =
286  llvm::ConstantInt::get(table_func_return->getType(), 0, true);
287  llvm::Value* is_ok = ir_builder->CreateICmpSGE(table_func_return, const_zero);
288  ir_builder->CreateCondBr(is_ok, bb_exit_0, bb_exit);
289 
290  ir_builder->SetInsertPoint(bb_exit_0);
291  llvm::Value* r =
292  ir_builder->CreateIntCast(table_func_return, get_int_type(64, ctx), true);
293  ir_builder->CreateStore(r, output_row_count_ptr);
294  ir_builder->CreateRet(const_zero);
295 
296  ir_builder->SetInsertPoint(bb_exit);
297  ir_builder->CreateRet(table_func_return);
298 }
const table_functions::TableFunction table_func
llvm::Type * get_int_type(const int width, llvm::LLVMContext &context)
std::string getName(const bool drop_suffix=false, const bool lower=false) const

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

TableFunctionCompilationContext& TableFunctionCompilationContext::operator= ( const TableFunctionCompilationContext )
delete
bool TableFunctionCompilationContext::passColumnsByValue ( const TableFunctionExecutionUnit exe_unit,
bool  is_gpu 
)
private

Definition at line 244 of file TableFunctionCompilationContext.cpp.

References table_functions::TableFunction::isRuntime(), rt_udf_cpu_module, rt_udf_gpu_module, and TableFunctionExecutionUnit::table_func.

Referenced by generateEntryPoint().

246  {
247  llvm::Module* mod = (is_gpu ? rt_udf_gpu_module.get() : rt_udf_cpu_module.get());
248  if (mod != nullptr) {
249  auto* flag = mod->getModuleFlag("pass_column_arguments_by_value");
250  if (auto* cnt = llvm::mdconst::extract_or_null<llvm::ConstantInt>(flag)) {
251  return cnt->getZExtValue();
252  }
253  }
254 
255  // fallback to original behavior
256  return exe_unit.table_func.isRuntime();
257 }
std::unique_ptr< llvm::Module > rt_udf_cpu_module
const table_functions::TableFunction table_func
std::unique_ptr< llvm::Module > rt_udf_gpu_module

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

Member Data Documentation

llvm::Function* TableFunctionCompilationContext::entry_point_func_
private
Executor* TableFunctionCompilationContext::executor_
private
llvm::Function* TableFunctionCompilationContext::kernel_func_
private

Definition at line 58 of file TableFunctionCompilationContext.h.

Referenced by finalize(), and generateGpuKernel().


The documentation for this class was generated from the following files: