OmniSciDB  04ee39c94c
ScalarCodeGenerator.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2019 OmniSci, 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 
17 #include "CodeGenerator.h"
18 #include "ScalarExprVisitor.h"
19 
20 namespace {
21 
22 class UsedColumnExpressions : public ScalarExprVisitor<ScalarCodeGenerator::ColumnMap> {
23  protected:
25  const Analyzer::ColumnVar* column) const override {
27  InputColDescriptor input_desc(
28  column->get_column_id(), column->get_table_id(), column->get_rte_idx());
29  m.emplace(input_desc,
30  std::static_pointer_cast<Analyzer::ColumnVar>(column->deep_copy()));
31  return m;
32  }
33 
35  const ScalarCodeGenerator::ColumnMap& aggregate,
36  const ScalarCodeGenerator::ColumnMap& next_result) const override {
37  auto result = aggregate;
38  result.insert(next_result.begin(), next_result.end());
39  return result;
40  }
41 };
42 
43 std::vector<InputTableInfo> g_table_infos;
44 
45 llvm::Type* llvm_type_from_sql(const SQLTypeInfo& ti, llvm::LLVMContext& ctx) {
46  switch (ti.get_type()) {
47  case kINT: {
48  return get_int_type(32, ctx);
49  }
50  default: {
51  LOG(FATAL) << "Unsupported type";
52  return nullptr; // satisfy -Wreturn-type
53  }
54  }
55 }
56 
57 } // namespace
58 
60  UsedColumnExpressions visitor;
61  const auto used_columns = visitor.visit(expr);
62  std::list<std::shared_ptr<const InputColDescriptor>> global_col_ids;
63  for (const auto& used_column : used_columns) {
64  global_col_ids.push_back(std::make_shared<InputColDescriptor>(
65  used_column.first.getColId(),
66  used_column.first.getScanDesc().getTableId(),
67  used_column.first.getScanDesc().getNestLevel()));
68  }
69  plan_state_->allocateLocalColumnIds(global_col_ids);
70  return used_columns;
71 }
72 
74  const Analyzer::Expr* expr,
75  const bool fetch_columns,
76  const CompilationOptions& co) {
77  own_plan_state_ = std::make_unique<PlanState>(false, nullptr);
78  plan_state_ = own_plan_state_.get();
79  const auto used_columns = prepare(expr);
80  std::vector<llvm::Type*> arg_types(plan_state_->global_to_local_col_ids_.size() + 1);
81  std::vector<std::shared_ptr<Analyzer::ColumnVar>> inputs(arg_types.size() - 1);
82  auto& ctx = module_->getContext();
83  for (const auto& kv : plan_state_->global_to_local_col_ids_) {
84  size_t arg_idx = kv.second;
85  CHECK_LT(arg_idx, arg_types.size());
86  const auto it = used_columns.find(kv.first);
87  const auto col_expr = it->second;
88  inputs[arg_idx] = col_expr;
89  const auto& ti = col_expr->get_type_info();
90  arg_types[arg_idx + 1] = llvm_type_from_sql(ti, ctx);
91  }
92  arg_types[0] =
93  llvm::PointerType::get(llvm_type_from_sql(expr->get_type_info(), ctx), 0);
94  auto ft = llvm::FunctionType::get(get_int_type(32, ctx), arg_types, false);
95  auto scalar_expr_func = llvm::Function::Create(
96  ft, llvm::Function::ExternalLinkage, "scalar_expr", module_.get());
97  auto bb_entry = llvm::BasicBlock::Create(ctx, ".entry", scalar_expr_func, 0);
98  own_cgen_state_ = std::make_unique<CgenState>(g_table_infos, false);
99  own_cgen_state_->module_ = module_.get();
100  own_cgen_state_->row_func_ = scalar_expr_func;
101  own_cgen_state_->ir_builder_.SetInsertPoint(bb_entry);
102  cgen_state_ = own_cgen_state_.get();
103  const auto expr_lvs = codegen(expr, fetch_columns, co);
104  CHECK_EQ(expr_lvs.size(), size_t(1));
105  cgen_state_->ir_builder_.CreateStore(expr_lvs.front(),
106  cgen_state_->row_func_->arg_begin());
107  cgen_state_->ir_builder_.CreateRet(ll_int<int32_t>(0, ctx));
109  std::vector<llvm::Type*> wrapper_arg_types(arg_types.size() + 1);
110  wrapper_arg_types[0] = llvm::PointerType::get(get_int_type(32, ctx), 0);
111  wrapper_arg_types[1] = arg_types[0];
112  for (size_t i = 1; i < arg_types.size(); ++i) {
113  wrapper_arg_types[i + 1] = llvm::PointerType::get(arg_types[i], 0);
114  }
115  auto wrapper_ft =
116  llvm::FunctionType::get(llvm::Type::getVoidTy(ctx), wrapper_arg_types, false);
117  auto wrapper_scalar_expr_func =
118  llvm::Function::Create(wrapper_ft,
119  llvm::Function::ExternalLinkage,
120  "wrapper_scalar_expr",
121  module_.get());
122  auto wrapper_bb_entry =
123  llvm::BasicBlock::Create(ctx, ".entry", wrapper_scalar_expr_func, 0);
124  llvm::IRBuilder<> b(ctx);
125  b.SetInsertPoint(wrapper_bb_entry);
126  std::vector<llvm::Value*> loaded_args = {wrapper_scalar_expr_func->arg_begin() + 1};
127  for (size_t i = 2; i < wrapper_arg_types.size(); ++i) {
128  loaded_args.push_back(b.CreateLoad(wrapper_scalar_expr_func->arg_begin() + i));
129  }
130  auto error_lv = b.CreateCall(scalar_expr_func, loaded_args);
131  b.CreateStore(error_lv, wrapper_scalar_expr_func->arg_begin());
132  b.CreateRetVoid();
133  return {scalar_expr_func, wrapper_scalar_expr_func, inputs};
134  }
135  return {scalar_expr_func, nullptr, inputs};
136 }
137 
139  const CompiledExpression& compiled_expression,
140  const CompilationOptions& co) {
141  CHECK(module_ && !execution_engine_.get()) << "Invalid code generator state";
142  module_.release();
143  switch (co.device_type_) {
145  execution_engine_ =
146  generateNativeCPUCode(compiled_expression.func, {compiled_expression.func}, co);
147  return {execution_engine_->getPointerToFunction(compiled_expression.func)};
148  }
150  return generateNativeGPUCode(
151  compiled_expression.func, compiled_expression.wrapper_func, co);
152  }
153  default: {
154  LOG(FATAL) << "Invalid device type";
155  return {}; // satisfy -Wreturn-type
156  }
157  }
158 }
159 
160 std::vector<llvm::Value*> ScalarCodeGenerator::codegenColumn(
161  const Analyzer::ColumnVar* column,
162  const bool fetch_column,
163  const CompilationOptions& co) {
164  int arg_idx = plan_state_->getLocalColumnId(column, fetch_column);
165  CHECK_LT(static_cast<size_t>(arg_idx), cgen_state_->row_func_->arg_size());
166  llvm::Value* arg = cgen_state_->row_func_->arg_begin() + arg_idx + 1;
167  return {arg};
168 }
169 
171  llvm::Function* func,
172  llvm::Function* wrapper_func,
173  const CompilationOptions& co) {
174  if (!nvptx_target_machine_) {
175  nvptx_target_machine_ = initializeNVPTXBackend();
176  }
177  if (!cuda_mgr_) {
178  cuda_mgr_ = std::make_unique<CudaMgr_Namespace::CudaMgr>(0);
179  }
180  const auto& dev_props = cuda_mgr_->getAllDeviceProperties();
181  int block_size = dev_props.front().maxThreadsPerBlock;
182  GPUTarget gpu_target;
183  gpu_target.nvptx_target_machine = nvptx_target_machine_.get();
184  gpu_target.cuda_mgr = cuda_mgr_.get();
185  gpu_target.block_size = block_size;
186  gpu_target.cgen_state = cgen_state_;
187  gpu_target.row_func_not_inlined = false;
188  const auto gpu_code = CodeGenerator::generateNativeGPUCode(
189  func, wrapper_func, {func, wrapper_func}, co, gpu_target);
190  for (const auto& cached_function : gpu_code.cached_functions) {
191  gpu_compilation_contexts_.emplace_back(std::get<1>(cached_function));
192  }
193  std::vector<void*> native_function_pointers;
194  for (const auto& cached_function : gpu_code.cached_functions) {
195  native_function_pointers.push_back(std::get<0>(cached_function));
196  }
197  return native_function_pointers;
198 }
ScalarCodeGenerator::ColumnMap visitColumnVar(const Analyzer::ColumnVar *column) const override
#define CHECK_EQ(x, y)
Definition: Logger.h:195
CompiledExpression compile(const Analyzer::Expr *expr, const bool fetch_columns, const CompilationOptions &co)
std::vector< llvm::Value * > codegenColumn(const Analyzer::ColumnVar *, const bool fetch_column, const CompilationOptions &) override
std::vector< void * > generateNativeCode(const CompiledExpression &compiled_expression, const CompilationOptions &co)
int get_column_id() const
Definition: Analyzer.h:194
llvm::Type * llvm_type_from_sql(const SQLTypeInfo &ti, llvm::LLVMContext &ctx)
#define LOG(tag)
Definition: Logger.h:182
HOST DEVICE SQLTypes get_type() const
Definition: sqltypes.h:323
std::shared_ptr< Analyzer::Expr > deep_copy() const override
Definition: Analyzer.cpp:59
llvm::Type * get_int_type(const int width, llvm::LLVMContext &context)
const CudaMgr_Namespace::CudaMgr * cuda_mgr
Definition: CodeGenerator.h:90
llvm::TargetMachine * nvptx_target_machine
Definition: CodeGenerator.h:89
ScalarCodeGenerator::ColumnMap aggregateResult(const ScalarCodeGenerator::ColumnMap &aggregate, const ScalarCodeGenerator::ColumnMap &next_result) const override
std::unordered_map< InputColDescriptor, std::shared_ptr< Analyzer::ColumnVar > > ColumnMap
static GPUCode generateNativeGPUCode(llvm::Function *func, llvm::Function *wrapper_func, const std::unordered_set< llvm::Function *> &live_funcs, const CompilationOptions &co, const GPUTarget &gpu_target)
ExecutorDeviceType device_type_
#define CHECK_LT(x, y)
Definition: Logger.h:197
int get_rte_idx() const
Definition: Analyzer.h:195
int get_table_id() const
Definition: Analyzer.h:193
ColumnMap prepare(const Analyzer::Expr *)
std::vector< void * > generateNativeGPUCode(llvm::Function *func, llvm::Function *wrapper_func, const CompilationOptions &co)
const SQLTypeInfo & get_type_info() const
Definition: Analyzer.h:77
#define CHECK(condition)
Definition: Logger.h:187
Definition: sqltypes.h:47