OmniSciDB  2b310ab3b2
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
InValuesIR.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2017 MapD Technologies, 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 "Execute.h"
19 
20 #include <future>
21 #include <memory>
22 
23 llvm::Value* CodeGenerator::codegen(const Analyzer::InValues* expr,
24  const CompilationOptions& co) {
26  const auto in_arg = expr->get_arg();
27  if (is_unnest(in_arg)) {
28  throw std::runtime_error("IN not supported for unnested expressions");
29  }
30  const auto& expr_ti = expr->get_type_info();
31  CHECK(expr_ti.is_boolean());
32  const auto lhs_lvs = codegen(in_arg, true, co);
33  llvm::Value* result{nullptr};
34  if (expr_ti.get_notnull()) {
35  result = llvm::ConstantInt::get(llvm::IntegerType::getInt1Ty(cgen_state_->context_),
36  false);
37  } else {
38  result = cgen_state_->llInt(int8_t(0));
39  }
40  CHECK(result);
41  if (co.hoist_literals) { // TODO(alex): remove this constraint
42  auto in_vals_bitmap = createInValuesBitmap(expr, co);
43  if (in_vals_bitmap) {
44  if (in_vals_bitmap->isEmpty()) {
45  return in_vals_bitmap->hasNull()
47  : result;
48  }
49  CHECK_EQ(size_t(1), lhs_lvs.size());
50  return cgen_state_->addInValuesBitmap(in_vals_bitmap)
51  ->codegen(lhs_lvs.front(), executor());
52  }
53  }
54  if (expr_ti.get_notnull()) {
55  for (auto in_val : expr->get_value_list()) {
56  result = cgen_state_->ir_builder_.CreateOr(
57  result,
58  toBool(
59  codegenCmp(kEQ, kONE, lhs_lvs, in_arg->get_type_info(), in_val.get(), co)));
60  }
61  } else {
62  for (auto in_val : expr->get_value_list()) {
63  const auto crt =
64  codegenCmp(kEQ, kONE, lhs_lvs, in_arg->get_type_info(), in_val.get(), co);
65  result = cgen_state_->emitCall("logical_or",
66  {result, crt, cgen_state_->inlineIntNull(expr_ti)});
67  }
68  }
69  return result;
70 }
71 
72 llvm::Value* CodeGenerator::codegen(const Analyzer::InIntegerSet* in_integer_set,
73  const CompilationOptions& co) {
75  const auto in_arg = in_integer_set->get_arg();
76  if (is_unnest(in_arg)) {
77  throw std::runtime_error("IN not supported for unnested expressions");
78  }
79  const auto& ti = in_integer_set->get_arg()->get_type_info();
80  const auto needle_null_val = inline_int_null_val(ti);
81  if (!co.hoist_literals) {
82  // We never run without literal hoisting in real world scenarios, this avoids a crash
83  // when testing.
84  throw std::runtime_error(
85  "IN subquery with many right-hand side values not supported when literal "
86  "hoisting is disabled");
87  }
88  auto in_vals_bitmap = std::make_unique<InValuesBitmap>(
89  in_integer_set->get_value_list(),
90  needle_null_val,
93  executor()->deviceCount(co.device_type),
94  &executor()->getCatalog()->getDataMgr());
95  const auto& in_integer_set_ti = in_integer_set->get_type_info();
96  CHECK(in_integer_set_ti.is_boolean());
97  const auto lhs_lvs = codegen(in_arg, true, co);
98  llvm::Value* result{nullptr};
99  if (in_integer_set_ti.get_notnull()) {
100  result = llvm::ConstantInt::get(llvm::IntegerType::getInt1Ty(cgen_state_->context_),
101  false);
102  } else {
103  result = cgen_state_->llInt(int8_t(0));
104  }
105  CHECK(result);
106  CHECK_EQ(size_t(1), lhs_lvs.size());
107  return cgen_state_->addInValuesBitmap(in_vals_bitmap)
108  ->codegen(lhs_lvs.front(), executor());
109 }
110 
111 std::unique_ptr<InValuesBitmap> CodeGenerator::createInValuesBitmap(
112  const Analyzer::InValues* in_values,
113  const CompilationOptions& co) {
115  const auto& value_list = in_values->get_value_list();
116  const auto val_count = value_list.size();
117  const auto& ti = in_values->get_arg()->get_type_info();
118  if (!(ti.is_integer() || (ti.is_string() && ti.get_compression() == kENCODING_DICT))) {
119  return nullptr;
120  }
121  const auto sdp =
122  ti.is_string() ? executor()->getStringDictionaryProxy(
123  ti.get_comp_param(), executor()->getRowSetMemoryOwner(), true)
124  : nullptr;
125  if (val_count > 3) {
126  using ListIterator = decltype(value_list.begin());
127  std::vector<int64_t> values;
128  const auto needle_null_val = inline_int_null_val(ti);
129  const int worker_count = val_count > 10000 ? cpu_threads() : int(1);
130  std::vector<std::vector<int64_t>> values_set(worker_count, std::vector<int64_t>());
131  std::vector<std::future<bool>> worker_threads;
132  auto start_it = value_list.begin();
133  for (size_t i = 0,
134  start_val = 0,
135  stride = (val_count + worker_count - 1) / worker_count;
136  i < val_count && start_val < val_count;
137  ++i, start_val += stride, std::advance(start_it, stride)) {
138  auto end_it = start_it;
139  std::advance(end_it, std::min(stride, val_count - start_val));
140  const auto do_work = [&](std::vector<int64_t>& out_vals,
141  const ListIterator start,
142  const ListIterator end) -> bool {
143  for (auto val_it = start; val_it != end; ++val_it) {
144  const auto& in_val = *val_it;
145  const auto in_val_const =
146  dynamic_cast<const Analyzer::Constant*>(extract_cast_arg(in_val.get()));
147  if (!in_val_const) {
148  return false;
149  }
150  const auto& in_val_ti = in_val->get_type_info();
151  CHECK(in_val_ti == ti || get_nullable_type_info(in_val_ti) == ti);
152  if (ti.is_string()) {
153  CHECK(sdp);
154  const auto string_id =
155  in_val_const->get_is_null()
156  ? needle_null_val
157  : sdp->getIdOfString(*in_val_const->get_constval().stringval);
158  if (string_id != StringDictionary::INVALID_STR_ID) {
159  out_vals.push_back(string_id);
160  }
161  } else {
162  out_vals.push_back(codegenIntConst(in_val_const)->getSExtValue());
163  }
164  }
165  return true;
166  };
167  if (worker_count > 1) {
168  worker_threads.push_back(std::async(
169  std::launch::async, do_work, std::ref(values_set[i]), start_it, end_it));
170  } else {
171  do_work(std::ref(values), start_it, end_it);
172  }
173  }
174  bool success = true;
175  for (auto& worker : worker_threads) {
176  success &= worker.get();
177  }
178  if (!success) {
179  return nullptr;
180  }
181  if (worker_count > 1) {
182  size_t total_val_count = 0;
183  for (auto& vals : values_set) {
184  total_val_count += vals.size();
185  }
186  values.reserve(total_val_count);
187  for (auto& vals : values_set) {
188  values.insert(values.end(), vals.begin(), vals.end());
189  }
190  }
191  try {
192  return std::make_unique<InValuesBitmap>(values,
193  needle_null_val,
197  executor()->deviceCount(co.device_type),
198  &executor()->getCatalog()->getDataMgr());
199  } catch (...) {
200  return nullptr;
201  }
202  }
203  return nullptr;
204 }
#define CHECK_EQ(x, y)
Definition: Logger.h:205
const std::vector< int64_t > & get_value_list() const
Definition: Analyzer.h:635
CgenState * cgen_state_
llvm::IRBuilder ir_builder_
Definition: CgenState.h:332
Definition: sqldefs.h:30
const Analyzer::Expr * extract_cast_arg(const Analyzer::Expr *expr)
Definition: Execute.h:130
llvm::LLVMContext & context_
Definition: CgenState.h:330
static constexpr int32_t INVALID_STR_ID
CHECK(cgen_state)
llvm::ConstantInt * inlineIntNull(const SQLTypeInfo &)
Definition: CgenState.cpp:27
const InValuesBitmap * addInValuesBitmap(std::unique_ptr< InValuesBitmap > &in_values_bitmap)
Definition: CgenState.h:203
#define AUTOMATIC_IR_METADATA(CGENSTATE)
const SQLTypeInfo & get_type_info() const
Definition: Analyzer.h:78
llvm::Value * emitCall(const std::string &fname, const std::vector< llvm::Value * > &args)
Definition: CgenState.cpp:137
ExecutorDeviceType device_type
std::vector< llvm::Value * > codegen(const Analyzer::Expr *, const bool fetch_columns, const CompilationOptions &)
Definition: IRCodegen.cpp:26
Definition: sqldefs.h:69
llvm::Value * codegen(llvm::Value *needle, Executor *executor) const
const std::list< std::shared_ptr< Analyzer::Expr > > & get_value_list() const
Definition: Analyzer.h:586
llvm::Value * toBool(llvm::Value *)
Definition: LogicalIR.cpp:335
llvm::Value * codegenCmp(const Analyzer::BinOper *, const CompilationOptions &)
Definition: CompareIR.cpp:184
llvm::ConstantInt * codegenIntConst(const Analyzer::Constant *constant)
Definition: ConstantIR.cpp:85
llvm::ConstantInt * llInt(const T v) const
Definition: CgenState.h:303
int64_t inline_int_null_val(const SQL_TYPE_INFO &ti)
std::unique_ptr< InValuesBitmap > createInValuesBitmap(const Analyzer::InValues *, const CompilationOptions &)
Definition: InValuesIR.cpp:111
bool is_unnest(const Analyzer::Expr *expr)
Definition: Execute.h:999
bool is_string() const
Definition: sqltypes.h:416
const Expr * get_arg() const
Definition: Analyzer.h:633
int cpu_threads()
Definition: thread_count.h:24
const Expr * get_arg() const
Definition: Analyzer.h:584
SQLTypeInfo get_nullable_type_info(const SQLTypeInfo &type_info)
Definition: sqltypes.h:834
Executor * executor() const