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