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