OmniSciDB  8fa3bf436f
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
IRCodegen.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 "../Parser/ParserNode.h"
18 #include "CodeGenerator.h"
19 #include "Execute.h"
20 #include "ExternalExecutor.h"
21 #include "MaxwellCodegenPatch.h"
22 #include "RelAlgTranslator.h"
23 
24 // Driver methods for the IR generation.
25 
27 
28 std::vector<llvm::Value*> CodeGenerator::codegen(const Analyzer::Expr* expr,
29  const bool fetch_columns,
30  const CompilationOptions& co) {
32  if (!expr) {
33  return {posArg(expr)};
34  }
35  auto bin_oper = dynamic_cast<const Analyzer::BinOper*>(expr);
36  if (bin_oper) {
37  return {codegen(bin_oper, co)};
38  }
39  auto u_oper = dynamic_cast<const Analyzer::UOper*>(expr);
40  if (u_oper) {
41  return {codegen(u_oper, co)};
42  }
43  auto col_var = dynamic_cast<const Analyzer::ColumnVar*>(expr);
44  if (col_var) {
45  return codegenColumn(col_var, fetch_columns, co);
46  }
47  auto constant = dynamic_cast<const Analyzer::Constant*>(expr);
48  if (constant) {
49  const auto& ti = constant->get_type_info();
50  if (ti.get_type() == kNULLT) {
51  throw std::runtime_error(
52  "NULL type literals are not currently supported in this context.");
53  }
54  if (constant->get_is_null()) {
55  return {ti.is_fp()
56  ? static_cast<llvm::Value*>(executor_->cgen_state_->inlineFpNull(ti))
57  : static_cast<llvm::Value*>(executor_->cgen_state_->inlineIntNull(ti))};
58  }
59  if (ti.get_compression() == kENCODING_DICT) {
60  // The dictionary encoding case should be handled by the parent expression
61  // (cast, for now), here is too late to know the dictionary id if not already set
62  CHECK_NE(ti.get_comp_param(), 0);
63  return {codegen(constant, ti.get_compression(), ti.get_comp_param(), co)};
64  }
65  return {codegen(constant, ti.get_compression(), 0, co)};
66  }
67  auto case_expr = dynamic_cast<const Analyzer::CaseExpr*>(expr);
68  if (case_expr) {
69  return {codegen(case_expr, co)};
70  }
71  auto extract_expr = dynamic_cast<const Analyzer::ExtractExpr*>(expr);
72  if (extract_expr) {
73  return {codegen(extract_expr, co)};
74  }
75  auto dateadd_expr = dynamic_cast<const Analyzer::DateaddExpr*>(expr);
76  if (dateadd_expr) {
77  return {codegen(dateadd_expr, co)};
78  }
79  auto datediff_expr = dynamic_cast<const Analyzer::DatediffExpr*>(expr);
80  if (datediff_expr) {
81  return {codegen(datediff_expr, co)};
82  }
83  auto datetrunc_expr = dynamic_cast<const Analyzer::DatetruncExpr*>(expr);
84  if (datetrunc_expr) {
85  return {codegen(datetrunc_expr, co)};
86  }
87  auto charlength_expr = dynamic_cast<const Analyzer::CharLengthExpr*>(expr);
88  if (charlength_expr) {
89  return {codegen(charlength_expr, co)};
90  }
91  auto keyforstring_expr = dynamic_cast<const Analyzer::KeyForStringExpr*>(expr);
92  if (keyforstring_expr) {
93  return {codegen(keyforstring_expr, co)};
94  }
95  auto sample_ratio_expr = dynamic_cast<const Analyzer::SampleRatioExpr*>(expr);
96  if (sample_ratio_expr) {
97  return {codegen(sample_ratio_expr, co)};
98  }
99  auto lower_expr = dynamic_cast<const Analyzer::LowerExpr*>(expr);
100  if (lower_expr) {
101  return {codegen(lower_expr, co)};
102  }
103  auto cardinality_expr = dynamic_cast<const Analyzer::CardinalityExpr*>(expr);
104  if (cardinality_expr) {
105  return {codegen(cardinality_expr, co)};
106  }
107  auto like_expr = dynamic_cast<const Analyzer::LikeExpr*>(expr);
108  if (like_expr) {
109  return {codegen(like_expr, co)};
110  }
111  auto regexp_expr = dynamic_cast<const Analyzer::RegexpExpr*>(expr);
112  if (regexp_expr) {
113  return {codegen(regexp_expr, co)};
114  }
115  auto likelihood_expr = dynamic_cast<const Analyzer::LikelihoodExpr*>(expr);
116  if (likelihood_expr) {
117  return {codegen(likelihood_expr->get_arg(), fetch_columns, co)};
118  }
119  auto in_expr = dynamic_cast<const Analyzer::InValues*>(expr);
120  if (in_expr) {
121  return {codegen(in_expr, co)};
122  }
123  auto in_integer_set_expr = dynamic_cast<const Analyzer::InIntegerSet*>(expr);
124  if (in_integer_set_expr) {
125  return {codegen(in_integer_set_expr, co)};
126  }
127  auto function_oper_with_custom_type_handling_expr =
128  dynamic_cast<const Analyzer::FunctionOperWithCustomTypeHandling*>(expr);
129  if (function_oper_with_custom_type_handling_expr) {
131  function_oper_with_custom_type_handling_expr, co)};
132  }
133  auto array_oper_expr = dynamic_cast<const Analyzer::ArrayExpr*>(expr);
134  if (array_oper_expr) {
135  return {codegenArrayExpr(array_oper_expr, co)};
136  }
137  auto geo_uop = dynamic_cast<const Analyzer::GeoUOper*>(expr);
138  if (geo_uop) {
139  return {codegenGeoUOper(geo_uop, co)};
140  }
141  auto geo_binop = dynamic_cast<const Analyzer::GeoBinOper*>(expr);
142  if (geo_binop) {
143  return {codegenGeoBinOper(geo_binop, co)};
144  }
145  auto function_oper_expr = dynamic_cast<const Analyzer::FunctionOper*>(expr);
146  if (function_oper_expr) {
147  return {codegenFunctionOper(function_oper_expr, co)};
148  }
149  if (dynamic_cast<const Analyzer::OffsetInFragment*>(expr)) {
150  return {posArg(nullptr)};
151  }
152  if (dynamic_cast<const Analyzer::WindowFunction*>(expr)) {
153  throw NativeExecutionError("Window expression not supported in this context");
154  }
155  abort();
156 }
157 
158 llvm::Value* CodeGenerator::codegen(const Analyzer::BinOper* bin_oper,
159  const CompilationOptions& co) {
161  const auto optype = bin_oper->get_optype();
162  if (IS_ARITHMETIC(optype)) {
163  return codegenArith(bin_oper, co);
164  }
165  if (IS_COMPARISON(optype)) {
166  return codegenCmp(bin_oper, co);
167  }
168  if (IS_LOGIC(optype)) {
169  return codegenLogical(bin_oper, co);
170  }
171  if (optype == kARRAY_AT) {
172  return codegenArrayAt(bin_oper, co);
173  }
174  abort();
175 }
176 
177 llvm::Value* CodeGenerator::codegen(const Analyzer::UOper* u_oper,
178  const CompilationOptions& co) {
180  const auto optype = u_oper->get_optype();
181  switch (optype) {
182  case kNOT: {
183  return codegenLogical(u_oper, co);
184  }
185  case kCAST: {
186  return codegenCast(u_oper, co);
187  }
188  case kUMINUS: {
189  return codegenUMinus(u_oper, co);
190  }
191  case kISNULL: {
192  return codegenIsNull(u_oper, co);
193  }
194  case kUNNEST:
195  return codegenUnnest(u_oper, co);
196  default:
197  abort();
198  }
199 }
200 
202  const CompilationOptions& co) {
204  auto input_expr = expr->get_arg();
205  CHECK(input_expr);
206 
207  auto double_lv = codegen(input_expr, true, co);
208  CHECK_EQ(size_t(1), double_lv.size());
209 
210  std::unique_ptr<CodeGenerator::NullCheckCodegen> nullcheck_codegen;
211  const bool is_nullable = !input_expr->get_type_info().get_notnull();
212  if (is_nullable) {
213  nullcheck_codegen = std::make_unique<NullCheckCodegen>(cgen_state_,
214  executor(),
215  double_lv.front(),
216  input_expr->get_type_info(),
217  "sample_ratio_nullcheck");
218  }
219  CHECK_EQ(input_expr->get_type_info().get_type(), kDOUBLE);
220  std::vector<llvm::Value*> args{double_lv[0], posArg(nullptr)};
221  auto ret = cgen_state_->emitCall("sample_ratio", args);
222  if (nullcheck_codegen) {
223  ret = nullcheck_codegen->finalize(ll_bool(false, cgen_state_->context_), ret);
224  }
225  return ret;
226 }
227 
228 namespace {
229 
231  const std::shared_ptr<Analyzer::Expr>& qual) {
232  const auto qual_cf = qual_to_conjunctive_form(qual);
233  ra_exe_unit.simple_quals.insert(ra_exe_unit.simple_quals.end(),
234  qual_cf.simple_quals.begin(),
235  qual_cf.simple_quals.end());
236  ra_exe_unit.quals.insert(
237  ra_exe_unit.quals.end(), qual_cf.quals.begin(), qual_cf.quals.end());
238 }
239 
241  const ExecutionOptions& eo,
242  const std::vector<InputTableInfo>& query_infos,
243  const size_t level_idx,
244  const std::string& fail_reason) {
245  if (eo.allow_loop_joins) {
246  return;
247  }
248  if (level_idx + 1 != ra_exe_unit.join_quals.size()) {
249  throw std::runtime_error(
250  "Hash join failed, reason(s): " + fail_reason +
251  " | Cannot fall back to loop join for intermediate join quals");
252  }
253  if (!is_trivial_loop_join(query_infos, ra_exe_unit)) {
254  throw std::runtime_error(
255  "Hash join failed, reason(s): " + fail_reason +
256  " | Cannot fall back to loop join for non-trivial inner table size");
257  }
258 }
259 
260 void check_valid_join_qual(std::shared_ptr<Analyzer::BinOper>& bin_oper) {
261  // check whether a join qual is valid before entering the hashtable build and codegen
262 
263  auto lhs_cv = dynamic_cast<const Analyzer::ColumnVar*>(bin_oper->get_left_operand());
264  auto rhs_cv = dynamic_cast<const Analyzer::ColumnVar*>(bin_oper->get_right_operand());
265  if (lhs_cv && rhs_cv && !bin_oper->is_overlaps_oper()) {
266  auto lhs_type = lhs_cv->get_type_info().get_type();
267  auto rhs_type = rhs_cv->get_type_info().get_type();
268  // check #1. avoid a join btw full array columns
269  if (lhs_type == SQLTypes::kARRAY && rhs_type == SQLTypes::kARRAY) {
270  throw std::runtime_error(
271  "Join operation between full array columns (i.e., R.arr = S.arr) instead of "
272  "indexed array columns (i.e., R.arr[1] = S.arr[2]) is not supported yet.");
273  }
274  }
275 }
276 
277 } // namespace
278 
279 std::vector<JoinLoop> Executor::buildJoinLoops(
280  RelAlgExecutionUnit& ra_exe_unit,
281  const CompilationOptions& co,
282  const ExecutionOptions& eo,
283  const std::vector<InputTableInfo>& query_infos,
284  ColumnCacheMap& column_cache) {
285  INJECT_TIMER(buildJoinLoops);
287  std::vector<JoinLoop> join_loops;
288  for (size_t level_idx = 0, current_hash_table_idx = 0;
289  level_idx < ra_exe_unit.join_quals.size();
290  ++level_idx) {
291  const auto& current_level_join_conditions = ra_exe_unit.join_quals[level_idx];
292  std::vector<std::string> fail_reasons;
293  const auto build_cur_level_hash_table = [&]() {
294  if (current_level_join_conditions.quals.size() > 1) {
295  const auto first_qual = *current_level_join_conditions.quals.begin();
296  auto qual_bin_oper =
297  std::dynamic_pointer_cast<const Analyzer::BinOper>(first_qual);
298  if (qual_bin_oper && qual_bin_oper->is_overlaps_oper() &&
299  current_level_join_conditions.type == JoinType::LEFT) {
300  JoinCondition join_condition{{first_qual}, current_level_join_conditions.type};
301 
302  return buildCurrentLevelHashTable(
303  join_condition, ra_exe_unit, co, query_infos, column_cache, fail_reasons);
304  }
305  }
306  return buildCurrentLevelHashTable(current_level_join_conditions,
307  ra_exe_unit,
308  co,
309  query_infos,
310  column_cache,
311  fail_reasons);
312  };
313  const auto current_level_hash_table = build_cur_level_hash_table();
314  const auto found_outer_join_matches_cb =
315  [this, level_idx](llvm::Value* found_outer_join_matches) {
319  found_outer_join_matches;
320  };
321  const auto is_deleted_cb = buildIsDeletedCb(ra_exe_unit, level_idx, co);
322  const auto outer_join_condition_multi_quals_cb =
323  [this, level_idx, &co, &current_level_join_conditions](
324  const std::vector<llvm::Value*>& prev_iters) {
325  // The values generated for the match path don't dominate all uses
326  // since on the non-match path nulls are generated. Reset the cache
327  // once the condition is generated to avoid incorrect reuse.
328  FetchCacheAnchor anchor(cgen_state_.get());
329  addJoinLoopIterator(prev_iters, level_idx + 1);
330  llvm::Value* left_join_cond = cgen_state_->llBool(true);
331  CodeGenerator code_generator(this);
332  // Do not want to look at all quals! only 1..N quals (ignore first qual)
333  // Note(jclay): this may need to support cases larger than 2
334  // are there any?
335  if (current_level_join_conditions.quals.size() >= 2) {
336  auto qual_it = std::next(current_level_join_conditions.quals.begin(), 1);
337  for (; qual_it != current_level_join_conditions.quals.end();
338  std::advance(qual_it, 1)) {
339  left_join_cond = cgen_state_->ir_builder_.CreateAnd(
340  left_join_cond,
341  code_generator.toBool(
342  code_generator.codegen(qual_it->get(), true, co).front()));
343  }
344  }
345  return left_join_cond;
346  };
347  if (current_level_hash_table) {
348  const auto hoisted_filters_cb = buildHoistLeftHandSideFiltersCb(
349  ra_exe_unit, level_idx, current_level_hash_table->getInnerTableId(), co);
350  if (current_level_hash_table->getHashType() == HashType::OneToOne) {
351  join_loops.emplace_back(
352  /*kind=*/JoinLoopKind::Singleton,
353  /*type=*/current_level_join_conditions.type,
354  /*iteration_domain_codegen=*/
355  [this, current_hash_table_idx, level_idx, current_level_hash_table, &co](
356  const std::vector<llvm::Value*>& prev_iters) {
357  addJoinLoopIterator(prev_iters, level_idx);
358  JoinLoopDomain domain{{0}};
359  domain.slot_lookup_result =
360  current_level_hash_table->codegenSlot(co, current_hash_table_idx);
361  return domain;
362  },
363  /*outer_condition_match=*/nullptr,
364  /*found_outer_matches=*/current_level_join_conditions.type == JoinType::LEFT
365  ? std::function<void(llvm::Value*)>(found_outer_join_matches_cb)
366  : nullptr,
367  /*hoisted_filters=*/hoisted_filters_cb,
368  /*is_deleted=*/is_deleted_cb);
369  } else {
370  join_loops.emplace_back(
371  /*kind=*/JoinLoopKind::Set,
372  /*type=*/current_level_join_conditions.type,
373  /*iteration_domain_codegen=*/
374  [this, current_hash_table_idx, level_idx, current_level_hash_table, &co](
375  const std::vector<llvm::Value*>& prev_iters) {
376  addJoinLoopIterator(prev_iters, level_idx);
377  JoinLoopDomain domain{{0}};
378  const auto matching_set = current_level_hash_table->codegenMatchingSet(
379  co, current_hash_table_idx);
380  domain.values_buffer = matching_set.elements;
381  domain.element_count = matching_set.count;
382  return domain;
383  },
384  /*outer_condition_match=*/
385  current_level_join_conditions.type == JoinType::LEFT
386  ? std::function<llvm::Value*(const std::vector<llvm::Value*>&)>(
387  outer_join_condition_multi_quals_cb)
388  : nullptr,
389  /*found_outer_matches=*/current_level_join_conditions.type == JoinType::LEFT
390  ? std::function<void(llvm::Value*)>(found_outer_join_matches_cb)
391  : nullptr,
392  /*hoisted_filters=*/hoisted_filters_cb,
393  /*is_deleted=*/is_deleted_cb);
394  }
395  ++current_hash_table_idx;
396  } else {
397  const auto fail_reasons_str = current_level_join_conditions.quals.empty()
398  ? "No equijoin expression found"
399  : boost::algorithm::join(fail_reasons, " | ");
401  ra_exe_unit, eo, query_infos, level_idx, fail_reasons_str);
402  // Callback provided to the `JoinLoop` framework to evaluate the (outer) join
403  // condition.
404  VLOG(1) << "Unable to build hash table, falling back to loop join: "
405  << fail_reasons_str;
406  const auto outer_join_condition_cb =
407  [this, level_idx, &co, &current_level_join_conditions](
408  const std::vector<llvm::Value*>& prev_iters) {
409  // The values generated for the match path don't dominate all uses
410  // since on the non-match path nulls are generated. Reset the cache
411  // once the condition is generated to avoid incorrect reuse.
412  FetchCacheAnchor anchor(cgen_state_.get());
413  addJoinLoopIterator(prev_iters, level_idx + 1);
414  llvm::Value* left_join_cond = cgen_state_->llBool(true);
415  CodeGenerator code_generator(this);
416  for (auto expr : current_level_join_conditions.quals) {
417  left_join_cond = cgen_state_->ir_builder_.CreateAnd(
418  left_join_cond,
419  code_generator.toBool(
420  code_generator.codegen(expr.get(), true, co).front()));
421  }
422  return left_join_cond;
423  };
424  join_loops.emplace_back(
425  /*kind=*/JoinLoopKind::UpperBound,
426  /*type=*/current_level_join_conditions.type,
427  /*iteration_domain_codegen=*/
428  [this, level_idx](const std::vector<llvm::Value*>& prev_iters) {
429  addJoinLoopIterator(prev_iters, level_idx);
430  JoinLoopDomain domain{{0}};
431  const auto rows_per_scan_ptr = cgen_state_->ir_builder_.CreateGEP(
432  get_arg_by_name(cgen_state_->row_func_, "num_rows_per_scan"),
433  cgen_state_->llInt(int32_t(level_idx + 1)));
434  domain.upper_bound = cgen_state_->ir_builder_.CreateLoad(rows_per_scan_ptr,
435  "num_rows_per_scan");
436  return domain;
437  },
438  /*outer_condition_match=*/
439  current_level_join_conditions.type == JoinType::LEFT
440  ? std::function<llvm::Value*(const std::vector<llvm::Value*>&)>(
441  outer_join_condition_cb)
442  : nullptr,
443  /*found_outer_matches=*/
444  current_level_join_conditions.type == JoinType::LEFT
445  ? std::function<void(llvm::Value*)>(found_outer_join_matches_cb)
446  : nullptr,
447  /*hoisted_filters=*/nullptr,
448  /*is_deleted=*/is_deleted_cb);
449  }
450  }
451  return join_loops;
452 }
453 
454 namespace {
455 
456 class ExprTableIdVisitor : public ScalarExprVisitor<std::set<int>> {
457  protected:
458  std::set<int> visitColumnVar(const Analyzer::ColumnVar* col_expr) const final {
459  return {col_expr->get_table_id()};
460  }
461 
462  std::set<int> visitFunctionOper(const Analyzer::FunctionOper* func_expr) const final {
463  std::set<int> ret;
464  for (size_t i = 0; i < func_expr->getArity(); i++) {
465  ret = aggregateResult(ret, visit(func_expr->getArg(i)));
466  }
467  return ret;
468  }
469 
470  std::set<int> visitBinOper(const Analyzer::BinOper* bin_oper) const final {
471  std::set<int> ret;
472  ret = aggregateResult(ret, visit(bin_oper->get_left_operand()));
473  return aggregateResult(ret, visit(bin_oper->get_right_operand()));
474  }
475 
476  std::set<int> visitUOper(const Analyzer::UOper* u_oper) const final {
477  return visit(u_oper->get_operand());
478  }
479 
480  std::set<int> aggregateResult(const std::set<int>& aggregate,
481  const std::set<int>& next_result) const final {
482  auto ret = aggregate; // copy
483  for (const auto& el : next_result) {
484  ret.insert(el);
485  }
486  return ret;
487  }
488 };
489 
490 } // namespace
491 
493  const RelAlgExecutionUnit& ra_exe_unit,
494  const size_t level_idx,
495  const int inner_table_id,
496  const CompilationOptions& co) {
498  return nullptr;
499  }
500 
501  const auto& current_level_join_conditions = ra_exe_unit.join_quals[level_idx];
502  if (current_level_join_conditions.type == JoinType::LEFT) {
503  const auto& condition = current_level_join_conditions.quals.front();
504  const auto bin_oper = dynamic_cast<const Analyzer::BinOper*>(condition.get());
505  CHECK(bin_oper) << condition->toString();
506  const auto rhs =
507  dynamic_cast<const Analyzer::ColumnVar*>(bin_oper->get_right_operand());
508  const auto lhs =
509  dynamic_cast<const Analyzer::ColumnVar*>(bin_oper->get_left_operand());
510  if (lhs && rhs && lhs->get_table_id() != rhs->get_table_id()) {
511  const Analyzer::ColumnVar* selected_lhs{nullptr};
512  // grab the left hand side column -- this is somewhat similar to normalize column
513  // pair, and a better solution may be to hoist that function out of the join
514  // framework and normalize columns at the top of build join loops
515  if (lhs->get_table_id() == inner_table_id) {
516  selected_lhs = rhs;
517  } else if (rhs->get_table_id() == inner_table_id) {
518  selected_lhs = lhs;
519  }
520  if (selected_lhs) {
521  std::list<std::shared_ptr<Analyzer::Expr>> hoisted_quals;
522  // get all LHS-only filters
523  auto should_hoist_qual = [&hoisted_quals](const auto& qual, const int table_id) {
524  CHECK(qual);
525 
526  ExprTableIdVisitor visitor;
527  const auto table_ids = visitor.visit(qual.get());
528  if (table_ids.size() == 1 && table_ids.find(table_id) != table_ids.end()) {
529  hoisted_quals.push_back(qual);
530  }
531  };
532  for (const auto& qual : ra_exe_unit.simple_quals) {
533  should_hoist_qual(qual, selected_lhs->get_table_id());
534  }
535  for (const auto& qual : ra_exe_unit.quals) {
536  should_hoist_qual(qual, selected_lhs->get_table_id());
537  }
538 
539  // build the filters callback and return it
540  if (!hoisted_quals.empty()) {
541  return [this, hoisted_quals, co](llvm::BasicBlock* true_bb,
542  llvm::BasicBlock* exit_bb,
543  const std::string& loop_name,
544  llvm::Function* parent_func,
545  CgenState* cgen_state) -> llvm::BasicBlock* {
546  // make sure we have quals to hoist
547  bool has_quals_to_hoist = false;
548  for (const auto& qual : hoisted_quals) {
549  // check to see if the filter was previously hoisted. if all filters were
550  // previously hoisted, this callback becomes a noop
551  if (plan_state_->hoisted_filters_.count(qual) == 0) {
552  has_quals_to_hoist = true;
553  break;
554  }
555  }
556 
557  if (!has_quals_to_hoist) {
558  return nullptr;
559  }
560 
561  AUTOMATIC_IR_METADATA(cgen_state);
562 
563  llvm::IRBuilder<>& builder = cgen_state->ir_builder_;
564  auto& context = builder.getContext();
565 
566  const auto filter_bb =
567  llvm::BasicBlock::Create(context,
568  "hoisted_left_join_filters_" + loop_name,
569  parent_func,
570  /*insert_before=*/true_bb);
571  builder.SetInsertPoint(filter_bb);
572 
573  llvm::Value* filter_lv = cgen_state_->llBool(true);
574  CodeGenerator code_generator(this);
576  for (const auto& qual : hoisted_quals) {
577  if (plan_state_->hoisted_filters_.insert(qual).second) {
578  // qual was inserted into the hoisted filters map, which means we have not
579  // seen this qual before. Generate filter.
580  VLOG(1) << "Generating code for hoisted left hand side qualifier "
581  << qual->toString();
582  auto cond = code_generator.toBool(
583  code_generator.codegen(qual.get(), true, co).front());
584  filter_lv = builder.CreateAnd(filter_lv, cond);
585  }
586  }
587  CHECK(filter_lv->getType()->isIntegerTy(1));
588 
589  builder.CreateCondBr(filter_lv, true_bb, exit_bb);
590  return filter_bb;
591  };
592  }
593  }
594  }
595  }
596  return nullptr;
597 }
598 
599 std::function<llvm::Value*(const std::vector<llvm::Value*>&, llvm::Value*)>
601  const size_t level_idx,
602  const CompilationOptions& co) {
604  if (!co.filter_on_deleted_column) {
605  return nullptr;
606  }
607  CHECK_LT(level_idx + 1, ra_exe_unit.input_descs.size());
608  const auto input_desc = ra_exe_unit.input_descs[level_idx + 1];
609  if (input_desc.getSourceType() != InputSourceType::TABLE) {
610  return nullptr;
611  }
612 
613  const auto deleted_cd = plan_state_->getDeletedColForTable(input_desc.getTableId());
614  if (!deleted_cd) {
615  return nullptr;
616  }
617  CHECK(deleted_cd->columnType.is_boolean());
618  const auto deleted_expr = makeExpr<Analyzer::ColumnVar>(deleted_cd->columnType,
619  input_desc.getTableId(),
620  deleted_cd->columnId,
621  input_desc.getNestLevel());
622  return [this, deleted_expr, level_idx, &co](const std::vector<llvm::Value*>& prev_iters,
623  llvm::Value* have_more_inner_rows) {
624  const auto matching_row_index = addJoinLoopIterator(prev_iters, level_idx + 1);
625  // Avoid fetching the deleted column from a position which is not valid.
626  // An invalid position can be returned by a one to one hash lookup (negative)
627  // or at the end of iteration over a set of matching values.
628  llvm::Value* is_valid_it{nullptr};
629  if (have_more_inner_rows) {
630  is_valid_it = have_more_inner_rows;
631  } else {
632  is_valid_it = cgen_state_->ir_builder_.CreateICmp(
633  llvm::ICmpInst::ICMP_SGE, matching_row_index, cgen_state_->llInt<int64_t>(0));
634  }
635  const auto it_valid_bb = llvm::BasicBlock::Create(
637  const auto it_not_valid_bb = llvm::BasicBlock::Create(
638  cgen_state_->context_, "it_not_valid", cgen_state_->current_func_);
639  cgen_state_->ir_builder_.CreateCondBr(is_valid_it, it_valid_bb, it_not_valid_bb);
640  const auto row_is_deleted_bb = llvm::BasicBlock::Create(
641  cgen_state_->context_, "row_is_deleted", cgen_state_->current_func_);
642  cgen_state_->ir_builder_.SetInsertPoint(it_valid_bb);
643  CodeGenerator code_generator(this);
644  const auto row_is_deleted = code_generator.toBool(
645  code_generator.codegen(deleted_expr.get(), true, co).front());
646  cgen_state_->ir_builder_.CreateBr(row_is_deleted_bb);
647  cgen_state_->ir_builder_.SetInsertPoint(it_not_valid_bb);
648  const auto row_is_deleted_default = cgen_state_->llBool(false);
649  cgen_state_->ir_builder_.CreateBr(row_is_deleted_bb);
650  cgen_state_->ir_builder_.SetInsertPoint(row_is_deleted_bb);
651  auto row_is_deleted_or_default =
652  cgen_state_->ir_builder_.CreatePHI(row_is_deleted->getType(), 2);
653  row_is_deleted_or_default->addIncoming(row_is_deleted, it_valid_bb);
654  row_is_deleted_or_default->addIncoming(row_is_deleted_default, it_not_valid_bb);
655  return row_is_deleted_or_default;
656  };
657 }
658 
659 std::shared_ptr<HashJoin> Executor::buildCurrentLevelHashTable(
660  const JoinCondition& current_level_join_conditions,
661  RelAlgExecutionUnit& ra_exe_unit,
662  const CompilationOptions& co,
663  const std::vector<InputTableInfo>& query_infos,
664  ColumnCacheMap& column_cache,
665  std::vector<std::string>& fail_reasons) {
667  if (current_level_join_conditions.type != JoinType::INNER &&
668  current_level_join_conditions.quals.size() > 1) {
669  fail_reasons.emplace_back("No equijoin expression found for outer join");
670  return nullptr;
671  }
672  std::shared_ptr<HashJoin> current_level_hash_table;
673  for (const auto& join_qual : current_level_join_conditions.quals) {
674  auto qual_bin_oper = std::dynamic_pointer_cast<Analyzer::BinOper>(join_qual);
675  if (!qual_bin_oper || !IS_EQUIVALENCE(qual_bin_oper->get_optype())) {
676  fail_reasons.emplace_back("No equijoin expression found");
677  if (current_level_join_conditions.type == JoinType::INNER) {
678  add_qualifier_to_execution_unit(ra_exe_unit, join_qual);
679  }
680  continue;
681  }
682  check_valid_join_qual(qual_bin_oper);
683  JoinHashTableOrError hash_table_or_error;
684  if (!current_level_hash_table) {
685  hash_table_or_error = buildHashTableForQualifier(
686  qual_bin_oper,
687  query_infos,
691  column_cache,
692  ra_exe_unit.query_hint);
693  current_level_hash_table = hash_table_or_error.hash_table;
694  }
695  if (hash_table_or_error.hash_table) {
696  plan_state_->join_info_.join_hash_tables_.push_back(hash_table_or_error.hash_table);
697  plan_state_->join_info_.equi_join_tautologies_.push_back(qual_bin_oper);
698  } else {
699  fail_reasons.push_back(hash_table_or_error.fail_reason);
700  if (current_level_join_conditions.type == JoinType::INNER) {
701  add_qualifier_to_execution_unit(ra_exe_unit, qual_bin_oper);
702  }
703  }
704  }
705  return current_level_hash_table;
706 }
707 
709  if (!cgen_state_->filter_func_) {
710  return;
711  }
712 
713  // Loop over all the instructions used in the filter func.
714  // The filter func instructions were generated as if for row func.
715  // Remap any values used by those instructions to filter func args
716  // and remember to forward them through the call in the row func.
717  for (auto bb_it = cgen_state_->filter_func_->begin();
718  bb_it != cgen_state_->filter_func_->end();
719  ++bb_it) {
720  for (auto instr_it = bb_it->begin(); instr_it != bb_it->end(); ++instr_it) {
721  size_t i = 0;
722  for (auto op_it = instr_it->value_op_begin(); op_it != instr_it->value_op_end();
723  ++op_it, ++i) {
724  llvm::Value* v = *op_it;
725 
726  // The last LLVM operand on a call instruction is the function to be called. Never
727  // remap it.
728  if (llvm::dyn_cast<const llvm::CallInst>(instr_it) &&
729  op_it == instr_it->value_op_end() - 1) {
730  continue;
731  }
732 
733  if (auto* instr = llvm::dyn_cast<llvm::Instruction>(v);
734  instr && instr->getParent() &&
735  instr->getParent()->getParent() == cgen_state_->row_func_) {
736  // Remember that this filter func arg is needed.
737  cgen_state_->filter_func_args_[v] = nullptr;
738  } else if (auto* argum = llvm::dyn_cast<llvm::Argument>(v);
739  argum && argum->getParent() == cgen_state_->row_func_) {
740  // Remember that this filter func arg is needed.
741  cgen_state_->filter_func_args_[v] = nullptr;
742  }
743  }
744  }
745  }
746 
747  // Create filter_func2 with parameters only for those row func values that are known to
748  // be used in the filter func code.
749  std::vector<llvm::Type*> filter_func_arg_types;
750  filter_func_arg_types.reserve(cgen_state_->filter_func_args_.v_.size());
751  for (auto& arg : cgen_state_->filter_func_args_.v_) {
752  filter_func_arg_types.push_back(arg->getType());
753  }
754  auto ft = llvm::FunctionType::get(
755  get_int_type(32, cgen_state_->context_), filter_func_arg_types, false);
756  cgen_state_->filter_func_->setName("old_filter_func");
757  auto filter_func2 = llvm::Function::Create(ft,
758  llvm::Function::ExternalLinkage,
759  "filter_func",
760  cgen_state_->filter_func_->getParent());
761  CHECK_EQ(filter_func2->arg_size(), cgen_state_->filter_func_args_.v_.size());
762  auto arg_it = cgen_state_->filter_func_args_.begin();
763  size_t i = 0;
764  for (llvm::Function::arg_iterator I = filter_func2->arg_begin(),
765  E = filter_func2->arg_end();
766  I != E;
767  ++I, ++arg_it) {
768  arg_it->second = &*I;
769  if (arg_it->first->hasName()) {
770  I->setName(arg_it->first->getName());
771  } else {
772  I->setName("extra" + std::to_string(i++));
773  }
774  }
775 
776  // copy the filter_func function body over
777  // see
778  // https://stackoverflow.com/questions/12864106/move-function-body-avoiding-full-cloning/18751365
779  filter_func2->getBasicBlockList().splice(
780  filter_func2->begin(), cgen_state_->filter_func_->getBasicBlockList());
781 
783  cgen_state_->current_func_ = filter_func2;
784  }
785  cgen_state_->filter_func_ = filter_func2;
786 
787  // loop over all the operands in the filter func
788  for (auto bb_it = cgen_state_->filter_func_->begin();
789  bb_it != cgen_state_->filter_func_->end();
790  ++bb_it) {
791  for (auto instr_it = bb_it->begin(); instr_it != bb_it->end(); ++instr_it) {
792  size_t i = 0;
793  for (auto op_it = instr_it->op_begin(); op_it != instr_it->op_end(); ++op_it, ++i) {
794  llvm::Value* v = op_it->get();
795  if (auto arg_it = cgen_state_->filter_func_args_.find(v);
796  arg_it != cgen_state_->filter_func_args_.end()) {
797  // replace row func value with a filter func arg
798  llvm::Use* use = &*op_it;
799  use->set(arg_it->second);
800  }
801  }
802  }
803  }
804 }
805 
806 llvm::Value* Executor::addJoinLoopIterator(const std::vector<llvm::Value*>& prev_iters,
807  const size_t level_idx) {
809  // Iterators are added for loop-outer joins when the head of the loop is generated,
810  // then once again when the body if generated. Allow this instead of special handling
811  // of call sites.
812  const auto it = cgen_state_->scan_idx_to_hash_pos_.find(level_idx);
813  if (it != cgen_state_->scan_idx_to_hash_pos_.end()) {
814  return it->second;
815  }
816  CHECK(!prev_iters.empty());
817  llvm::Value* matching_row_index = prev_iters.back();
818  const auto it_ok =
819  cgen_state_->scan_idx_to_hash_pos_.emplace(level_idx, matching_row_index);
820  CHECK(it_ok.second);
821  return matching_row_index;
822 }
823 
824 void Executor::codegenJoinLoops(const std::vector<JoinLoop>& join_loops,
825  const RelAlgExecutionUnit& ra_exe_unit,
826  GroupByAndAggregate& group_by_and_aggregate,
827  llvm::Function* query_func,
828  llvm::BasicBlock* entry_bb,
830  const CompilationOptions& co,
831  const ExecutionOptions& eo) {
833  const auto exit_bb =
834  llvm::BasicBlock::Create(cgen_state_->context_, "exit", cgen_state_->current_func_);
835  cgen_state_->ir_builder_.SetInsertPoint(exit_bb);
836  cgen_state_->ir_builder_.CreateRet(cgen_state_->llInt<int32_t>(0));
837  cgen_state_->ir_builder_.SetInsertPoint(entry_bb);
838  CodeGenerator code_generator(this);
839  const auto loops_entry_bb = JoinLoop::codegen(
840  join_loops,
841  /*body_codegen=*/
842  [this,
843  query_func,
844  &query_mem_desc,
845  &co,
846  &eo,
847  &group_by_and_aggregate,
848  &join_loops,
849  &ra_exe_unit](const std::vector<llvm::Value*>& prev_iters) {
851  addJoinLoopIterator(prev_iters, join_loops.size());
852  auto& builder = cgen_state_->ir_builder_;
853  const auto loop_body_bb = llvm::BasicBlock::Create(
854  builder.getContext(), "loop_body", builder.GetInsertBlock()->getParent());
855  builder.SetInsertPoint(loop_body_bb);
856  const bool can_return_error =
857  compileBody(ra_exe_unit, group_by_and_aggregate, query_mem_desc, co);
858  if (can_return_error || cgen_state_->needs_error_check_ ||
860  createErrorCheckControlFlow(query_func,
863  co.device_type,
864  group_by_and_aggregate.query_infos_);
865  }
866  return loop_body_bb;
867  },
868  /*outer_iter=*/code_generator.posArg(nullptr),
869  exit_bb,
870  cgen_state_.get());
871  cgen_state_->ir_builder_.SetInsertPoint(entry_bb);
872  cgen_state_->ir_builder_.CreateBr(loops_entry_bb);
873 }
874 
876  Analyzer::Expr* group_by_col,
877  const size_t col_width,
878  const CompilationOptions& co,
879  const bool translate_null_val,
880  const int64_t translated_null_val,
881  DiamondCodegen& diamond_codegen,
882  std::stack<llvm::BasicBlock*>& array_loops,
883  const bool thread_mem_shared) {
885  CHECK_GE(col_width, sizeof(int32_t));
886  CodeGenerator code_generator(this);
887  auto group_key = code_generator.codegen(group_by_col, true, co).front();
888  auto key_to_cache = group_key;
889  if (dynamic_cast<Analyzer::UOper*>(group_by_col) &&
890  static_cast<Analyzer::UOper*>(group_by_col)->get_optype() == kUNNEST) {
891  auto preheader = cgen_state_->ir_builder_.GetInsertBlock();
892  auto array_loop_head = llvm::BasicBlock::Create(cgen_state_->context_,
893  "array_loop_head",
895  preheader->getNextNode());
896  diamond_codegen.setFalseTarget(array_loop_head);
897  const auto ret_ty = get_int_type(32, cgen_state_->context_);
898  auto array_idx_ptr = cgen_state_->ir_builder_.CreateAlloca(ret_ty);
899  CHECK(array_idx_ptr);
900  cgen_state_->ir_builder_.CreateStore(cgen_state_->llInt(int32_t(0)), array_idx_ptr);
901  const auto arr_expr = static_cast<Analyzer::UOper*>(group_by_col)->get_operand();
902  const auto& array_ti = arr_expr->get_type_info();
903  CHECK(array_ti.is_array());
904  const auto& elem_ti = array_ti.get_elem_type();
905  auto array_len =
906  (array_ti.get_size() > 0)
907  ? cgen_state_->llInt(array_ti.get_size() / elem_ti.get_size())
909  "array_size",
910  ret_ty,
911  {group_key,
912  code_generator.posArg(arr_expr),
913  cgen_state_->llInt(log2_bytes(elem_ti.get_logical_size()))});
914  cgen_state_->ir_builder_.CreateBr(array_loop_head);
915  cgen_state_->ir_builder_.SetInsertPoint(array_loop_head);
916  CHECK(array_len);
917  auto array_idx = cgen_state_->ir_builder_.CreateLoad(array_idx_ptr);
918  auto bound_check = cgen_state_->ir_builder_.CreateICmp(
919  llvm::ICmpInst::ICMP_SLT, array_idx, array_len);
920  auto array_loop_body = llvm::BasicBlock::Create(
921  cgen_state_->context_, "array_loop_body", cgen_state_->current_func_);
922  cgen_state_->ir_builder_.CreateCondBr(
923  bound_check,
924  array_loop_body,
925  array_loops.empty() ? diamond_codegen.orig_cond_false_ : array_loops.top());
926  cgen_state_->ir_builder_.SetInsertPoint(array_loop_body);
927  cgen_state_->ir_builder_.CreateStore(
928  cgen_state_->ir_builder_.CreateAdd(array_idx, cgen_state_->llInt(int32_t(1))),
929  array_idx_ptr);
930  auto array_at_fname = "array_at_" + numeric_type_name(elem_ti);
931  if (array_ti.get_size() < 0) {
932  if (array_ti.get_notnull()) {
933  array_at_fname = "notnull_" + array_at_fname;
934  }
935  array_at_fname = "varlen_" + array_at_fname;
936  }
937  const auto ar_ret_ty =
938  elem_ti.is_fp()
939  ? (elem_ti.get_type() == kDOUBLE
940  ? llvm::Type::getDoubleTy(cgen_state_->context_)
941  : llvm::Type::getFloatTy(cgen_state_->context_))
942  : get_int_type(elem_ti.get_logical_size() * 8, cgen_state_->context_);
943  group_key = cgen_state_->emitExternalCall(
944  array_at_fname,
945  ar_ret_ty,
946  {group_key, code_generator.posArg(arr_expr), array_idx});
948  elem_ti, isArchMaxwell(co.device_type), thread_mem_shared)) {
949  key_to_cache = spillDoubleElement(group_key, ar_ret_ty);
950  } else {
951  key_to_cache = group_key;
952  }
953  CHECK(array_loop_head);
954  array_loops.push(array_loop_head);
955  }
956  cgen_state_->group_by_expr_cache_.push_back(key_to_cache);
957  llvm::Value* orig_group_key{nullptr};
958  if (translate_null_val) {
959  const std::string translator_func_name(
960  col_width == sizeof(int32_t) ? "translate_null_key_i32_" : "translate_null_key_");
961  const auto& ti = group_by_col->get_type_info();
962  const auto key_type = get_int_type(ti.get_logical_size() * 8, cgen_state_->context_);
963  orig_group_key = group_key;
964  group_key = cgen_state_->emitCall(
965  translator_func_name + numeric_type_name(ti),
966  {group_key,
967  static_cast<llvm::Value*>(
968  llvm::ConstantInt::get(key_type, inline_int_null_val(ti))),
969  static_cast<llvm::Value*>(llvm::ConstantInt::get(
970  llvm::Type::getInt64Ty(cgen_state_->context_), translated_null_val))});
971  }
972  group_key = cgen_state_->ir_builder_.CreateBitCast(
973  cgen_state_->castToTypeIn(group_key, col_width * 8),
974  get_int_type(col_width * 8, cgen_state_->context_));
975  if (orig_group_key) {
976  orig_group_key = cgen_state_->ir_builder_.CreateBitCast(
977  cgen_state_->castToTypeIn(orig_group_key, col_width * 8),
978  get_int_type(col_width * 8, cgen_state_->context_));
979  }
980  return {group_key, orig_group_key};
981 }
982 
984  Executor* executor,
985  llvm::Value* nullable_lv,
986  const SQLTypeInfo& nullable_ti,
987  const std::string& name)
988  : cgen_state(cgen_state), name(name) {
989  AUTOMATIC_IR_METADATA(cgen_state);
990  CHECK(nullable_ti.is_number() || nullable_ti.is_time());
991 
992  null_check = std::make_unique<DiamondCodegen>(
993  nullable_ti.is_fp()
994  ? cgen_state->ir_builder_.CreateFCmp(llvm::FCmpInst::FCMP_OEQ,
995  nullable_lv,
996  cgen_state->inlineFpNull(nullable_ti))
997  : cgen_state->ir_builder_.CreateICmp(llvm::ICmpInst::ICMP_EQ,
998  nullable_lv,
999  cgen_state->inlineIntNull(nullable_ti)),
1000  executor,
1001  false,
1002  name,
1003  nullptr,
1004  false);
1005 
1006  // generate a phi node depending on whether we got a null or not
1007  nullcheck_bb = llvm::BasicBlock::Create(
1008  cgen_state->context_, name + "_bb", cgen_state->current_func_);
1009 
1010  // update the blocks created by diamond codegen to point to the newly created phi
1011  // block
1012  cgen_state->ir_builder_.SetInsertPoint(null_check->cond_true_);
1013  cgen_state->ir_builder_.CreateBr(nullcheck_bb);
1014  cgen_state->ir_builder_.SetInsertPoint(null_check->cond_false_);
1015 }
1016 
1017 llvm::Value* CodeGenerator::NullCheckCodegen::finalize(llvm::Value* null_lv,
1018  llvm::Value* notnull_lv) {
1019  AUTOMATIC_IR_METADATA(cgen_state);
1020  CHECK(null_check);
1021  cgen_state->ir_builder_.CreateBr(nullcheck_bb);
1022 
1023  CHECK_EQ(null_lv->getType(), notnull_lv->getType());
1024 
1025  cgen_state->ir_builder_.SetInsertPoint(nullcheck_bb);
1026  nullcheck_value =
1027  cgen_state->ir_builder_.CreatePHI(null_lv->getType(), 2, name + "_value");
1028  nullcheck_value->addIncoming(notnull_lv, null_check->cond_false_);
1029  nullcheck_value->addIncoming(null_lv, null_check->cond_true_);
1030 
1031  null_check.reset(nullptr);
1032  cgen_state->ir_builder_.SetInsertPoint(nullcheck_bb);
1033  return nullcheck_value;
1034 }
JoinInfo join_info_
Definition: PlanState.h:64
std::shared_ptr< HashJoin > buildCurrentLevelHashTable(const JoinCondition &current_level_join_conditions, RelAlgExecutionUnit &ra_exe_unit, const CompilationOptions &co, const std::vector< InputTableInfo > &query_infos, ColumnCacheMap &column_cache, std::vector< std::string > &fail_reasons)
Definition: IRCodegen.cpp:659
#define CHECK_EQ(x, y)
Definition: Logger.h:211
llvm::Value * castToTypeIn(llvm::Value *val, const size_t bit_width)
Definition: CgenState.cpp:112
bool g_enable_left_join_filter_hoisting
Definition: Execute.cpp:94
NullCheckCodegen(CgenState *cgen_state, Executor *executor, llvm::Value *nullable_lv, const SQLTypeInfo &nullable_ti, const std::string &name="")
Definition: IRCodegen.cpp:983
#define IS_LOGIC(X)
Definition: sqldefs.h:60
std::vector< llvm::Value * > outer_join_match_found_per_level_
Definition: CgenState.h:340
llvm::BasicBlock * nullcheck_bb
bool is_trivial_loop_join(const std::vector< InputTableInfo > &query_infos, const RelAlgExecutionUnit &ra_exe_unit)
Definition: Execute.cpp:1154
void codegenJoinLoops(const std::vector< JoinLoop > &join_loops, const RelAlgExecutionUnit &ra_exe_unit, GroupByAndAggregate &group_by_and_aggregate, llvm::Function *query_func, llvm::BasicBlock *entry_bb, const QueryMemoryDescriptor &query_mem_desc, const CompilationOptions &co, const ExecutionOptions &eo)
Definition: IRCodegen.cpp:824
llvm::Value * values_buffer
Definition: JoinLoop.h:48
#define IS_EQUIVALENCE(X)
Definition: sqldefs.h:67
llvm::Value * codegenArith(const Analyzer::BinOper *, const CompilationOptions &)
CgenState * cgen_state_
std::set< int > aggregateResult(const std::set< int > &aggregate, const std::set< int > &next_result) const final
Definition: IRCodegen.cpp:480
GroupColLLVMValue groupByColumnCodegen(Analyzer::Expr *group_by_col, const size_t col_width, const CompilationOptions &, const bool translate_null_val, const int64_t translated_null_val, DiamondCodegen &, std::stack< llvm::BasicBlock * > &, const bool thread_mem_shared)
Definition: IRCodegen.cpp:875
bool is_fp() const
Definition: sqltypes.h:493
llvm::Value * emitExternalCall(const std::string &fname, llvm::Type *ret_type, const std::vector< llvm::Value * > args, const std::vector< llvm::Attribute::AttrKind > &fnattrs={}, const bool has_struct_return=false)
Definition: CgenState.h:222
llvm::IRBuilder ir_builder_
Definition: CgenState.h:329
std::function< llvm::BasicBlock *(llvm::BasicBlock *, llvm::BasicBlock *, const std::string &, llvm::Function *, CgenState *)> HoistedFiltersCallback
Definition: JoinLoop.h:60
string name
Definition: setup.in.py:72
llvm::Value * posArg(const Analyzer::Expr *) const
Definition: ColumnIR.cpp:512
std::string join(T const &container, std::string const &delim)
std::vector< InputDescriptor > input_descs
#define CHECK_GE(x, y)
Definition: Logger.h:216
bool need_patch_unnest_double(const SQLTypeInfo &ti, const bool is_maxwell, const bool mem_shared)
std::set< int > visitColumnVar(const Analyzer::ColumnVar *col_expr) const final
Definition: IRCodegen.cpp:458
Definition: sqldefs.h:49
llvm::ConstantInt * llBool(const bool v) const
Definition: CgenState.h:314
virtual std::vector< llvm::Value * > codegenColumn(const Analyzer::ColumnVar *, const bool fetch_column, const CompilationOptions &)
Definition: ColumnIR.cpp:92
InsertionOrderedMap filter_func_args_
Definition: CgenState.h:342
llvm::Value * codegenArrayAt(const Analyzer::BinOper *, const CompilationOptions &)
Definition: ArrayIR.cpp:26
HOST DEVICE SQLTypes get_type() const
Definition: sqltypes.h:314
void setFalseTarget(llvm::BasicBlock *cond_false)
QualsConjunctiveForm qual_to_conjunctive_form(const std::shared_ptr< Analyzer::Expr > qual_expr)
llvm::Type * get_int_type(const int width, llvm::LLVMContext &context)
bool is_number() const
Definition: sqltypes.h:494
std::vector< llvm::Value * > codegenGeoBinOper(const Analyzer::GeoBinOper *, const CompilationOptions &)
Definition: GeoIR.cpp:86
bool is_time() const
Definition: sqltypes.h:495
std::shared_ptr< HashJoin > hash_table
Definition: Execute.h:840
std::string to_string(char const *&&v)
llvm::Function * row_func_
Definition: CgenState.h:319
llvm::Value * codegenIsNull(const Analyzer::UOper *, const CompilationOptions &)
Definition: LogicalIR.cpp:380
SQLOps get_optype() const
Definition: Analyzer.h:439
std::vector< llvm::Value * > group_by_expr_cache_
Definition: CgenState.h:336
std::set< int > visitUOper(const Analyzer::UOper *u_oper) const final
Definition: IRCodegen.cpp:476
llvm::LLVMContext & context_
Definition: CgenState.h:327
llvm::Function * current_func_
Definition: CgenState.h:321
llvm::Value * get_arg_by_name(llvm::Function *func, const std::string &name)
Definition: Execute.h:167
std::vector< llvm::Value * > v_
#define INJECT_TIMER(DESC)
Definition: measure.h:93
#define CHECK_NE(x, y)
Definition: Logger.h:212
const JoinQualsPerNestingLevel join_quals
std::vector< llvm::Value * > codegenGeoUOper(const Analyzer::GeoUOper *, const CompilationOptions &)
Definition: GeoIR.cpp:21
llvm::ConstantInt * inlineIntNull(const SQLTypeInfo &)
Definition: CgenState.cpp:28
llvm::Value * codegenFunctionOper(const Analyzer::FunctionOper *, const CompilationOptions &)
std::set< int > visitFunctionOper(const Analyzer::FunctionOper *func_expr) const final
Definition: IRCodegen.cpp:462
Executor * executor_
static llvm::BasicBlock * codegen(const std::vector< JoinLoop > &join_loops, const std::function< llvm::BasicBlock *(const std::vector< llvm::Value * > &)> &body_codegen, llvm::Value *outer_iter, llvm::BasicBlock *exit_bb, CgenState *cgen_state)
Definition: JoinLoop.cpp:48
void add_qualifier_to_execution_unit(RelAlgExecutionUnit &ra_exe_unit, const std::shared_ptr< Analyzer::Expr > &qual)
Definition: IRCodegen.cpp:230
std::unordered_map< int, llvm::Value * > scan_idx_to_hash_pos_
Definition: CgenState.h:341
bool needs_error_check_
Definition: CgenState.h:344
std::vector< llvm::Value * > codegenArrayExpr(const Analyzer::ArrayExpr *, const CompilationOptions &)
Definition: ArrayIR.cpp:91
#define AUTOMATIC_IR_METADATA(CGENSTATE)
llvm::BasicBlock * orig_cond_false_
const SQLTypeInfo & get_type_info() const
Definition: Analyzer.h:78
llvm::Value * codegenUMinus(const Analyzer::UOper *, const CompilationOptions &)
llvm::Value * emitCall(const std::string &fname, const std::vector< llvm::Value * > &args)
Definition: CgenState.cpp:174
llvm::Value * slot_lookup_result
Definition: JoinLoop.h:46
std::set< int > visitBinOper(const Analyzer::BinOper *bin_oper) const final
Definition: IRCodegen.cpp:470
ExecutorDeviceType device_type
std::unordered_map< int, std::unordered_map< int, std::shared_ptr< const ColumnarResults >>> ColumnCacheMap
PlanState * plan_state_
std::vector< llvm::Value * > codegen(const Analyzer::Expr *, const bool fetch_columns, const CompilationOptions &)
Definition: IRCodegen.cpp:28
#define CHECK_LT(x, y)
Definition: Logger.h:213
const std::vector< InputTableInfo > & query_infos_
llvm::Function * filter_func_
Definition: CgenState.h:320
#define IS_ARITHMETIC(X)
Definition: sqldefs.h:61
const ColumnDescriptor * getDeletedColForTable(const TableId table_id)
Definition: PlanState.h:84
const Expr * get_arg() const
Definition: Analyzer.h:750
auto find(llvm::Value *key)
Expression class for the LOWER (lowercase) string function. The &quot;arg&quot; constructor parameter must be a...
Definition: Analyzer.h:791
llvm::Value * toBool(llvm::Value *)
Definition: LogicalIR.cpp:343
llvm::Value * codegenFunctionOperWithCustomTypeHandling(const Analyzer::FunctionOperWithCustomTypeHandling *, const CompilationOptions &)
llvm::Value * codegenCmp(const Analyzer::BinOper *, const CompilationOptions &)
Definition: CompareIR.cpp:230
HoistedFiltersSet hoisted_filters_
Definition: PlanState.h:59
std::list< std::shared_ptr< Analyzer::Expr > > quals
llvm::ConstantInt * llInt(const T v) const
Definition: CgenState.h:300
llvm::Value * codegenUnnest(const Analyzer::UOper *, const CompilationOptions &)
Definition: ArrayIR.cpp:20
llvm::Value * addJoinLoopIterator(const std::vector< llvm::Value * > &prev_iters, const size_t level_idx)
Definition: IRCodegen.cpp:806
std::list< std::shared_ptr< Analyzer::Expr > > quals
RegisteredQueryHint query_hint
llvm::Value * finalize(llvm::Value *null_lv, llvm::Value *notnull_lv)
Definition: IRCodegen.cpp:1017
#define CHECK(condition)
Definition: Logger.h:203
llvm::Value * codegenLogical(const Analyzer::BinOper *, const CompilationOptions &)
Definition: LogicalIR.cpp:298
void check_if_loop_join_is_allowed(RelAlgExecutionUnit &ra_exe_unit, const ExecutionOptions &eo, const std::vector< InputTableInfo > &query_infos, const size_t level_idx, const std::string &fail_reason)
Definition: IRCodegen.cpp:240
int64_t inline_int_null_val(const SQL_TYPE_INFO &ti)
llvm::ConstantInt * ll_bool(const bool v, llvm::LLVMContext &context)
JoinLoop::HoistedFiltersCallback buildHoistLeftHandSideFiltersCb(const RelAlgExecutionUnit &ra_exe_unit, const size_t level_idx, const int inner_table_id, const CompilationOptions &co)
Definition: IRCodegen.cpp:492
llvm::Value * codegenCast(const Analyzer::UOper *, const CompilationOptions &)
Definition: CastIR.cpp:20
uint32_t log2_bytes(const uint32_t bytes)
Definition: Execute.h:177
std::string numeric_type_name(const SQLTypeInfo &ti)
Definition: Execute.h:210
void redeclareFilterFunction()
Definition: IRCodegen.cpp:708
std::vector< JoinLoop > buildJoinLoops(RelAlgExecutionUnit &ra_exe_unit, const CompilationOptions &co, const ExecutionOptions &eo, const std::vector< InputTableInfo > &query_infos, ColumnCacheMap &column_cache)
Definition: IRCodegen.cpp:279
std::function< llvm::Value *(const std::vector< llvm::Value * > &, llvm::Value *)> buildIsDeletedCb(const RelAlgExecutionUnit &ra_exe_unit, const size_t level_idx, const CompilationOptions &co)
Definition: IRCodegen.cpp:600
Definition: sqldefs.h:39
SQLOps get_optype() const
Definition: Analyzer.h:370
#define VLOG(n)
Definition: Logger.h:297
std::unique_ptr< DiamondCodegen > null_check
std::list< std::shared_ptr< Analyzer::Expr > > simple_quals
#define IS_COMPARISON(X)
Definition: sqldefs.h:57
llvm::ConstantFP * inlineFpNull(const SQLTypeInfo &)
Definition: CgenState.cpp:66
void check_valid_join_qual(std::shared_ptr< Analyzer::BinOper > &bin_oper)
Definition: IRCodegen.cpp:260
Executor * executor() const