OmniSciDB  1dac507f6e
 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 
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  CHECK_EQ(size_t(1), lhs_lvs.size());
104  return cgen_state_->addInValuesBitmap(in_vals_bitmap)
105  ->codegen(lhs_lvs.front(), executor());
106 }
107 
108 std::unique_ptr<InValuesBitmap> CodeGenerator::createInValuesBitmap(
109  const Analyzer::InValues* in_values,
110  const CompilationOptions& co) {
111  const auto& value_list = in_values->get_value_list();
112  const auto val_count = value_list.size();
113  const auto& ti = in_values->get_arg()->get_type_info();
114  if (!(ti.is_integer() || (ti.is_string() && ti.get_compression() == kENCODING_DICT))) {
115  return nullptr;
116  }
117  const auto sdp =
118  ti.is_string() ? executor()->getStringDictionaryProxy(
119  ti.get_comp_param(), executor()->getRowSetMemoryOwner(), true)
120  : nullptr;
121  if (val_count > 3) {
122  using ListIterator = decltype(value_list.begin());
123  std::vector<int64_t> values;
124  const auto needle_null_val = inline_int_null_val(ti);
125  const int worker_count = val_count > 10000 ? cpu_threads() : int(1);
126  std::vector<std::vector<int64_t>> values_set(worker_count, std::vector<int64_t>());
127  std::vector<std::future<bool>> worker_threads;
128  auto start_it = value_list.begin();
129  for (size_t i = 0,
130  start_val = 0,
131  stride = (val_count + worker_count - 1) / worker_count;
132  i < val_count && start_val < val_count;
133  ++i, start_val += stride, std::advance(start_it, stride)) {
134  auto end_it = start_it;
135  std::advance(end_it, std::min(stride, val_count - start_val));
136  const auto do_work = [&](std::vector<int64_t>& out_vals,
137  const ListIterator start,
138  const ListIterator end) -> bool {
139  for (auto val_it = start; val_it != end; ++val_it) {
140  const auto& in_val = *val_it;
141  const auto in_val_const =
142  dynamic_cast<const Analyzer::Constant*>(extract_cast_arg(in_val.get()));
143  if (!in_val_const) {
144  return false;
145  }
146  const auto& in_val_ti = in_val->get_type_info();
147  CHECK(in_val_ti == ti);
148  if (ti.is_string()) {
149  CHECK(sdp);
150  const auto string_id =
151  in_val_const->get_is_null()
152  ? needle_null_val
153  : sdp->getIdOfString(*in_val_const->get_constval().stringval);
154  if (string_id != StringDictionary::INVALID_STR_ID) {
155  out_vals.push_back(string_id);
156  }
157  } else {
158  out_vals.push_back(codegenIntConst(in_val_const)->getSExtValue());
159  }
160  }
161  return true;
162  };
163  if (worker_count > 1) {
164  worker_threads.push_back(std::async(
165  std::launch::async, do_work, std::ref(values_set[i]), start_it, end_it));
166  } else {
167  do_work(std::ref(values), start_it, end_it);
168  }
169  }
170  bool success = true;
171  for (auto& worker : worker_threads) {
172  success &= worker.get();
173  }
174  if (!success) {
175  return nullptr;
176  }
177  if (worker_count > 1) {
178  size_t total_val_count = 0;
179  for (auto& vals : values_set) {
180  total_val_count += vals.size();
181  }
182  values.reserve(total_val_count);
183  for (auto& vals : values_set) {
184  values.insert(values.end(), vals.begin(), vals.end());
185  }
186  }
187  try {
188  return boost::make_unique<InValuesBitmap>(values,
189  needle_null_val,
193  executor()->deviceCount(co.device_type_),
194  &executor()->getCatalog()->getDataMgr());
195  } catch (...) {
196  return nullptr;
197  }
198  }
199  return nullptr;
200 }
#define CHECK_EQ(x, y)
Definition: Logger.h:198
const std::vector< int64_t > & get_value_list() const
Definition: Analyzer.h:629
CgenState * cgen_state_
llvm::IRBuilder ir_builder_
Definition: CgenState.h:269
Definition: sqldefs.h:30
const Analyzer::Expr * extract_cast_arg(const Analyzer::Expr *expr)
Definition: Execute.h:152
llvm::LLVMContext & context_
Definition: CgenState.h:267
static constexpr int32_t INVALID_STR_ID
CHECK(cgen_state)
llvm::ConstantInt * inlineIntNull(const SQLTypeInfo &)
Definition: CgenState.cpp:24
const InValuesBitmap * addInValuesBitmap(std::unique_ptr< InValuesBitmap > &in_values_bitmap)
Definition: CgenState.h:195
SQLTypeInfoCore< ArrayContextTypeSizer, ExecutorTypePackaging, DateTimeFacilities > SQLTypeInfo
Definition: sqltypes.h:852
const SQLTypeInfo & get_type_info() const
Definition: Analyzer.h:78
ExecutorDeviceType device_type_
llvm::Value * emitCall(const std::string &fname, const std::vector< llvm::Value * > &args)
Definition: CgenState.cpp:134
std::vector< llvm::Value * > codegen(const Analyzer::Expr *, const bool fetch_columns, const CompilationOptions &)
Definition: IRCodegen.cpp:25
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:580
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
llvm::ConstantInt * llInt(const T v) const
Definition: CgenState.h:248
bool is_string() const
Definition: sqltypes.h:477
int64_t inline_int_null_val(const SQL_TYPE_INFO &ti)
std::unique_ptr< InValuesBitmap > createInValuesBitmap(const Analyzer::InValues *, const CompilationOptions &)
Definition: InValuesIR.cpp:108
bool is_unnest(const Analyzer::Expr *expr)
Definition: Execute.h:1090
const Expr * get_arg() const
Definition: Analyzer.h:627
int cpu_threads()
Definition: thread_count.h:25
const Expr * get_arg() const
Definition: Analyzer.h:578
Executor * executor() const