OmniSciDB  a667adc9c8
 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, &selected_lhs](const auto& qual,
524  const int table_id) {
525  CHECK(qual);
526 
527  ExprTableIdVisitor visitor;
528  const auto table_ids = visitor.visit(qual.get());
529  if (table_ids.size() == 1 && table_ids.find(table_id) != table_ids.end()) {
530  hoisted_quals.push_back(qual);
531  }
532  };
533  for (const auto& qual : ra_exe_unit.simple_quals) {
534  should_hoist_qual(qual, selected_lhs->get_table_id());
535  }
536  for (const auto& qual : ra_exe_unit.quals) {
537  should_hoist_qual(qual, selected_lhs->get_table_id());
538  }
539 
540  // build the filters callback and return it
541  if (!hoisted_quals.empty()) {
542  return [this, hoisted_quals, co](llvm::BasicBlock* true_bb,
543  llvm::BasicBlock* exit_bb,
544  const std::string& loop_name,
545  llvm::Function* parent_func,
546  CgenState* cgen_state) -> llvm::BasicBlock* {
547  // make sure we have quals to hoist
548  bool has_quals_to_hoist = false;
549  for (const auto& qual : hoisted_quals) {
550  // check to see if the filter was previously hoisted. if all filters were
551  // previously hoisted, this callback becomes a noop
552  if (plan_state_->hoisted_filters_.count(qual) == 0) {
553  has_quals_to_hoist = true;
554  break;
555  }
556  }
557 
558  if (!has_quals_to_hoist) {
559  return nullptr;
560  }
561 
562  AUTOMATIC_IR_METADATA(cgen_state);
563 
564  llvm::IRBuilder<>& builder = cgen_state->ir_builder_;
565  auto& context = builder.getContext();
566 
567  const auto filter_bb =
568  llvm::BasicBlock::Create(context,
569  "hoisted_left_join_filters_" + loop_name,
570  parent_func,
571  /*insert_before=*/true_bb);
572  builder.SetInsertPoint(filter_bb);
573 
574  llvm::Value* filter_lv = cgen_state_->llBool(true);
575  CodeGenerator code_generator(this);
577  for (const auto& qual : hoisted_quals) {
578  if (plan_state_->hoisted_filters_.insert(qual).second) {
579  // qual was inserted into the hoisted filters map, which means we have not
580  // seen this qual before. Generate filter.
581  VLOG(1) << "Generating code for hoisted left hand side qualifier "
582  << qual->toString();
583  auto cond = code_generator.toBool(
584  code_generator.codegen(qual.get(), true, co).front());
585  filter_lv = builder.CreateAnd(filter_lv, cond);
586  }
587  }
588  CHECK(filter_lv->getType()->isIntegerTy(1));
589 
590  builder.CreateCondBr(filter_lv, true_bb, exit_bb);
591  return filter_bb;
592  };
593  }
594  }
595  }
596  }
597  return nullptr;
598 }
599 
600 std::function<llvm::Value*(const std::vector<llvm::Value*>&, llvm::Value*)>
602  const size_t level_idx,
603  const CompilationOptions& co) {
605  if (!co.filter_on_deleted_column) {
606  return nullptr;
607  }
608  CHECK_LT(level_idx + 1, ra_exe_unit.input_descs.size());
609  const auto input_desc = ra_exe_unit.input_descs[level_idx + 1];
610  if (input_desc.getSourceType() != InputSourceType::TABLE) {
611  return nullptr;
612  }
613 
614  const auto deleted_cd = plan_state_->getDeletedColForTable(input_desc.getTableId());
615  if (!deleted_cd) {
616  return nullptr;
617  }
618  CHECK(deleted_cd->columnType.is_boolean());
619  const auto deleted_expr = makeExpr<Analyzer::ColumnVar>(deleted_cd->columnType,
620  input_desc.getTableId(),
621  deleted_cd->columnId,
622  input_desc.getNestLevel());
623  return [this, deleted_expr, level_idx, &co](const std::vector<llvm::Value*>& prev_iters,
624  llvm::Value* have_more_inner_rows) {
625  const auto matching_row_index = addJoinLoopIterator(prev_iters, level_idx + 1);
626  // Avoid fetching the deleted column from a position which is not valid.
627  // An invalid position can be returned by a one to one hash lookup (negative)
628  // or at the end of iteration over a set of matching values.
629  llvm::Value* is_valid_it{nullptr};
630  if (have_more_inner_rows) {
631  is_valid_it = have_more_inner_rows;
632  } else {
633  is_valid_it = cgen_state_->ir_builder_.CreateICmp(
634  llvm::ICmpInst::ICMP_SGE, matching_row_index, cgen_state_->llInt<int64_t>(0));
635  }
636  const auto it_valid_bb = llvm::BasicBlock::Create(
638  const auto it_not_valid_bb = llvm::BasicBlock::Create(
639  cgen_state_->context_, "it_not_valid", cgen_state_->current_func_);
640  cgen_state_->ir_builder_.CreateCondBr(is_valid_it, it_valid_bb, it_not_valid_bb);
641  const auto row_is_deleted_bb = llvm::BasicBlock::Create(
642  cgen_state_->context_, "row_is_deleted", cgen_state_->current_func_);
643  cgen_state_->ir_builder_.SetInsertPoint(it_valid_bb);
644  CodeGenerator code_generator(this);
645  const auto row_is_deleted = code_generator.toBool(
646  code_generator.codegen(deleted_expr.get(), true, co).front());
647  cgen_state_->ir_builder_.CreateBr(row_is_deleted_bb);
648  cgen_state_->ir_builder_.SetInsertPoint(it_not_valid_bb);
649  const auto row_is_deleted_default = cgen_state_->llBool(false);
650  cgen_state_->ir_builder_.CreateBr(row_is_deleted_bb);
651  cgen_state_->ir_builder_.SetInsertPoint(row_is_deleted_bb);
652  auto row_is_deleted_or_default =
653  cgen_state_->ir_builder_.CreatePHI(row_is_deleted->getType(), 2);
654  row_is_deleted_or_default->addIncoming(row_is_deleted, it_valid_bb);
655  row_is_deleted_or_default->addIncoming(row_is_deleted_default, it_not_valid_bb);
656  return row_is_deleted_or_default;
657  };
658 }
659 
660 std::shared_ptr<HashJoin> Executor::buildCurrentLevelHashTable(
661  const JoinCondition& current_level_join_conditions,
662  RelAlgExecutionUnit& ra_exe_unit,
663  const CompilationOptions& co,
664  const std::vector<InputTableInfo>& query_infos,
665  ColumnCacheMap& column_cache,
666  std::vector<std::string>& fail_reasons) {
668  if (current_level_join_conditions.type != JoinType::INNER &&
669  current_level_join_conditions.quals.size() > 1) {
670  fail_reasons.emplace_back("No equijoin expression found for outer join");
671  return nullptr;
672  }
673  std::shared_ptr<HashJoin> current_level_hash_table;
674  for (const auto& join_qual : current_level_join_conditions.quals) {
675  auto qual_bin_oper = std::dynamic_pointer_cast<Analyzer::BinOper>(join_qual);
676  if (!qual_bin_oper || !IS_EQUIVALENCE(qual_bin_oper->get_optype())) {
677  fail_reasons.emplace_back("No equijoin expression found");
678  if (current_level_join_conditions.type == JoinType::INNER) {
679  add_qualifier_to_execution_unit(ra_exe_unit, join_qual);
680  }
681  continue;
682  }
683  check_valid_join_qual(qual_bin_oper);
684  JoinHashTableOrError hash_table_or_error;
685  if (!current_level_hash_table) {
686  hash_table_or_error = buildHashTableForQualifier(
687  qual_bin_oper,
688  query_infos,
692  column_cache,
693  ra_exe_unit.query_hint);
694  current_level_hash_table = hash_table_or_error.hash_table;
695  }
696  if (hash_table_or_error.hash_table) {
697  plan_state_->join_info_.join_hash_tables_.push_back(hash_table_or_error.hash_table);
698  plan_state_->join_info_.equi_join_tautologies_.push_back(qual_bin_oper);
699  } else {
700  fail_reasons.push_back(hash_table_or_error.fail_reason);
701  if (current_level_join_conditions.type == JoinType::INNER) {
702  add_qualifier_to_execution_unit(ra_exe_unit, qual_bin_oper);
703  }
704  }
705  }
706  return current_level_hash_table;
707 }
708 
710  if (!cgen_state_->filter_func_) {
711  return;
712  }
713 
714  // Loop over all the instructions used in the filter func.
715  // The filter func instructions were generated as if for row func.
716  // Remap any values used by those instructions to filter func args
717  // and remember to forward them through the call in the row func.
718  for (auto bb_it = cgen_state_->filter_func_->begin();
719  bb_it != cgen_state_->filter_func_->end();
720  ++bb_it) {
721  for (auto instr_it = bb_it->begin(); instr_it != bb_it->end(); ++instr_it) {
722  size_t i = 0;
723  for (auto op_it = instr_it->value_op_begin(); op_it != instr_it->value_op_end();
724  ++op_it, ++i) {
725  llvm::Value* v = *op_it;
726 
727  // The last LLVM operand on a call instruction is the function to be called. Never
728  // remap it.
729  if (llvm::dyn_cast<const llvm::CallInst>(instr_it) &&
730  op_it == instr_it->value_op_end() - 1) {
731  continue;
732  }
733 
734  if (auto* instr = llvm::dyn_cast<llvm::Instruction>(v);
735  instr && instr->getParent() &&
736  instr->getParent()->getParent() == cgen_state_->row_func_) {
737  // Remember that this filter func arg is needed.
738  cgen_state_->filter_func_args_[v] = nullptr;
739  } else if (auto* argum = llvm::dyn_cast<llvm::Argument>(v);
740  argum && argum->getParent() == cgen_state_->row_func_) {
741  // Remember that this filter func arg is needed.
742  cgen_state_->filter_func_args_[v] = nullptr;
743  }
744  }
745  }
746  }
747 
748  // Create filter_func2 with parameters only for those row func values that are known to
749  // be used in the filter func code.
750  std::vector<llvm::Type*> filter_func_arg_types;
751  filter_func_arg_types.reserve(cgen_state_->filter_func_args_.v_.size());
752  for (auto& arg : cgen_state_->filter_func_args_.v_) {
753  filter_func_arg_types.push_back(arg->getType());
754  }
755  auto ft = llvm::FunctionType::get(
756  get_int_type(32, cgen_state_->context_), filter_func_arg_types, false);
757  cgen_state_->filter_func_->setName("old_filter_func");
758  auto filter_func2 = llvm::Function::Create(ft,
759  llvm::Function::ExternalLinkage,
760  "filter_func",
761  cgen_state_->filter_func_->getParent());
762  CHECK_EQ(filter_func2->arg_size(), cgen_state_->filter_func_args_.v_.size());
763  auto arg_it = cgen_state_->filter_func_args_.begin();
764  size_t i = 0;
765  for (llvm::Function::arg_iterator I = filter_func2->arg_begin(),
766  E = filter_func2->arg_end();
767  I != E;
768  ++I, ++arg_it) {
769  arg_it->second = &*I;
770  if (arg_it->first->hasName()) {
771  I->setName(arg_it->first->getName());
772  } else {
773  I->setName("extra" + std::to_string(i++));
774  }
775  }
776 
777  // copy the filter_func function body over
778  // see
779  // https://stackoverflow.com/questions/12864106/move-function-body-avoiding-full-cloning/18751365
780  filter_func2->getBasicBlockList().splice(
781  filter_func2->begin(), cgen_state_->filter_func_->getBasicBlockList());
782 
784  cgen_state_->current_func_ = filter_func2;
785  }
786  cgen_state_->filter_func_ = filter_func2;
787 
788  // loop over all the operands in the filter func
789  for (auto bb_it = cgen_state_->filter_func_->begin();
790  bb_it != cgen_state_->filter_func_->end();
791  ++bb_it) {
792  for (auto instr_it = bb_it->begin(); instr_it != bb_it->end(); ++instr_it) {
793  size_t i = 0;
794  for (auto op_it = instr_it->op_begin(); op_it != instr_it->op_end(); ++op_it, ++i) {
795  llvm::Value* v = op_it->get();
796  if (auto arg_it = cgen_state_->filter_func_args_.find(v);
797  arg_it != cgen_state_->filter_func_args_.end()) {
798  // replace row func value with a filter func arg
799  llvm::Use* use = &*op_it;
800  use->set(arg_it->second);
801  }
802  }
803  }
804  }
805 }
806 
807 llvm::Value* Executor::addJoinLoopIterator(const std::vector<llvm::Value*>& prev_iters,
808  const size_t level_idx) {
810  // Iterators are added for loop-outer joins when the head of the loop is generated,
811  // then once again when the body if generated. Allow this instead of special handling
812  // of call sites.
813  const auto it = cgen_state_->scan_idx_to_hash_pos_.find(level_idx);
814  if (it != cgen_state_->scan_idx_to_hash_pos_.end()) {
815  return it->second;
816  }
817  CHECK(!prev_iters.empty());
818  llvm::Value* matching_row_index = prev_iters.back();
819  const auto it_ok =
820  cgen_state_->scan_idx_to_hash_pos_.emplace(level_idx, matching_row_index);
821  CHECK(it_ok.second);
822  return matching_row_index;
823 }
824 
825 void Executor::codegenJoinLoops(const std::vector<JoinLoop>& join_loops,
826  const RelAlgExecutionUnit& ra_exe_unit,
827  GroupByAndAggregate& group_by_and_aggregate,
828  llvm::Function* query_func,
829  llvm::BasicBlock* entry_bb,
831  const CompilationOptions& co,
832  const ExecutionOptions& eo) {
834  const auto exit_bb =
835  llvm::BasicBlock::Create(cgen_state_->context_, "exit", cgen_state_->current_func_);
836  cgen_state_->ir_builder_.SetInsertPoint(exit_bb);
837  cgen_state_->ir_builder_.CreateRet(cgen_state_->llInt<int32_t>(0));
838  cgen_state_->ir_builder_.SetInsertPoint(entry_bb);
839  CodeGenerator code_generator(this);
840  const auto loops_entry_bb = JoinLoop::codegen(
841  join_loops,
842  /*body_codegen=*/
843  [this,
844  query_func,
845  &query_mem_desc,
846  &co,
847  &eo,
848  &group_by_and_aggregate,
849  &join_loops,
850  &ra_exe_unit](const std::vector<llvm::Value*>& prev_iters) {
852  addJoinLoopIterator(prev_iters, join_loops.size());
853  auto& builder = cgen_state_->ir_builder_;
854  const auto loop_body_bb = llvm::BasicBlock::Create(
855  builder.getContext(), "loop_body", builder.GetInsertBlock()->getParent());
856  builder.SetInsertPoint(loop_body_bb);
857  const bool can_return_error =
858  compileBody(ra_exe_unit, group_by_and_aggregate, query_mem_desc, co);
859  if (can_return_error || cgen_state_->needs_error_check_ ||
861  createErrorCheckControlFlow(query_func,
864  co.device_type,
865  group_by_and_aggregate.query_infos_);
866  }
867  return loop_body_bb;
868  },
869  /*outer_iter=*/code_generator.posArg(nullptr),
870  exit_bb,
871  cgen_state_.get());
872  cgen_state_->ir_builder_.SetInsertPoint(entry_bb);
873  cgen_state_->ir_builder_.CreateBr(loops_entry_bb);
874 }
875 
877  Analyzer::Expr* group_by_col,
878  const size_t col_width,
879  const CompilationOptions& co,
880  const bool translate_null_val,
881  const int64_t translated_null_val,
882  GroupByAndAggregate::DiamondCodegen& diamond_codegen,
883  std::stack<llvm::BasicBlock*>& array_loops,
884  const bool thread_mem_shared) {
886  CHECK_GE(col_width, sizeof(int32_t));
887  CodeGenerator code_generator(this);
888  auto group_key = code_generator.codegen(group_by_col, true, co).front();
889  auto key_to_cache = group_key;
890  if (dynamic_cast<Analyzer::UOper*>(group_by_col) &&
891  static_cast<Analyzer::UOper*>(group_by_col)->get_optype() == kUNNEST) {
892  auto preheader = cgen_state_->ir_builder_.GetInsertBlock();
893  auto array_loop_head = llvm::BasicBlock::Create(cgen_state_->context_,
894  "array_loop_head",
896  preheader->getNextNode());
897  diamond_codegen.setFalseTarget(array_loop_head);
898  const auto ret_ty = get_int_type(32, cgen_state_->context_);
899  auto array_idx_ptr = cgen_state_->ir_builder_.CreateAlloca(ret_ty);
900  CHECK(array_idx_ptr);
901  cgen_state_->ir_builder_.CreateStore(cgen_state_->llInt(int32_t(0)), array_idx_ptr);
902  const auto arr_expr = static_cast<Analyzer::UOper*>(group_by_col)->get_operand();
903  const auto& array_ti = arr_expr->get_type_info();
904  CHECK(array_ti.is_array());
905  const auto& elem_ti = array_ti.get_elem_type();
906  auto array_len =
907  (array_ti.get_size() > 0)
908  ? cgen_state_->llInt(array_ti.get_size() / elem_ti.get_size())
910  "array_size",
911  ret_ty,
912  {group_key,
913  code_generator.posArg(arr_expr),
914  cgen_state_->llInt(log2_bytes(elem_ti.get_logical_size()))});
915  cgen_state_->ir_builder_.CreateBr(array_loop_head);
916  cgen_state_->ir_builder_.SetInsertPoint(array_loop_head);
917  CHECK(array_len);
918  auto array_idx = cgen_state_->ir_builder_.CreateLoad(array_idx_ptr);
919  auto bound_check = cgen_state_->ir_builder_.CreateICmp(
920  llvm::ICmpInst::ICMP_SLT, array_idx, array_len);
921  auto array_loop_body = llvm::BasicBlock::Create(
922  cgen_state_->context_, "array_loop_body", cgen_state_->current_func_);
923  cgen_state_->ir_builder_.CreateCondBr(
924  bound_check,
925  array_loop_body,
926  array_loops.empty() ? diamond_codegen.orig_cond_false_ : array_loops.top());
927  cgen_state_->ir_builder_.SetInsertPoint(array_loop_body);
928  cgen_state_->ir_builder_.CreateStore(
929  cgen_state_->ir_builder_.CreateAdd(array_idx, cgen_state_->llInt(int32_t(1))),
930  array_idx_ptr);
931  auto array_at_fname = "array_at_" + numeric_type_name(elem_ti);
932  if (array_ti.get_size() < 0) {
933  if (array_ti.get_notnull()) {
934  array_at_fname = "notnull_" + array_at_fname;
935  }
936  array_at_fname = "varlen_" + array_at_fname;
937  }
938  const auto ar_ret_ty =
939  elem_ti.is_fp()
940  ? (elem_ti.get_type() == kDOUBLE
941  ? llvm::Type::getDoubleTy(cgen_state_->context_)
942  : llvm::Type::getFloatTy(cgen_state_->context_))
943  : get_int_type(elem_ti.get_logical_size() * 8, cgen_state_->context_);
944  group_key = cgen_state_->emitExternalCall(
945  array_at_fname,
946  ar_ret_ty,
947  {group_key, code_generator.posArg(arr_expr), array_idx});
949  elem_ti, isArchMaxwell(co.device_type), thread_mem_shared)) {
950  key_to_cache = spillDoubleElement(group_key, ar_ret_ty);
951  } else {
952  key_to_cache = group_key;
953  }
954  CHECK(array_loop_head);
955  array_loops.push(array_loop_head);
956  }
957  cgen_state_->group_by_expr_cache_.push_back(key_to_cache);
958  llvm::Value* orig_group_key{nullptr};
959  if (translate_null_val) {
960  const std::string translator_func_name(
961  col_width == sizeof(int32_t) ? "translate_null_key_i32_" : "translate_null_key_");
962  const auto& ti = group_by_col->get_type_info();
963  const auto key_type = get_int_type(ti.get_logical_size() * 8, cgen_state_->context_);
964  orig_group_key = group_key;
965  group_key = cgen_state_->emitCall(
966  translator_func_name + numeric_type_name(ti),
967  {group_key,
968  static_cast<llvm::Value*>(
969  llvm::ConstantInt::get(key_type, inline_int_null_val(ti))),
970  static_cast<llvm::Value*>(llvm::ConstantInt::get(
971  llvm::Type::getInt64Ty(cgen_state_->context_), translated_null_val))});
972  }
973  group_key = cgen_state_->ir_builder_.CreateBitCast(
974  cgen_state_->castToTypeIn(group_key, col_width * 8),
975  get_int_type(col_width * 8, cgen_state_->context_));
976  if (orig_group_key) {
977  orig_group_key = cgen_state_->ir_builder_.CreateBitCast(
978  cgen_state_->castToTypeIn(orig_group_key, col_width * 8),
979  get_int_type(col_width * 8, cgen_state_->context_));
980  }
981  return {group_key, orig_group_key};
982 }
983 
985  Executor* executor,
986  llvm::Value* nullable_lv,
987  const SQLTypeInfo& nullable_ti,
988  const std::string& name)
989  : cgen_state(cgen_state), name(name) {
990  AUTOMATIC_IR_METADATA(cgen_state);
991  CHECK(nullable_ti.is_number() || nullable_ti.is_time());
992 
993  null_check = std::make_unique<GroupByAndAggregate::DiamondCodegen>(
994  nullable_ti.is_fp()
995  ? cgen_state->ir_builder_.CreateFCmp(llvm::FCmpInst::FCMP_OEQ,
996  nullable_lv,
997  cgen_state->inlineFpNull(nullable_ti))
998  : cgen_state->ir_builder_.CreateICmp(llvm::ICmpInst::ICMP_EQ,
999  nullable_lv,
1000  cgen_state->inlineIntNull(nullable_ti)),
1001  executor,
1002  false,
1003  name,
1004  nullptr,
1005  false);
1006 
1007  // generate a phi node depending on whether we got a null or not
1008  nullcheck_bb = llvm::BasicBlock::Create(
1009  cgen_state->context_, name + "_bb", cgen_state->current_func_);
1010 
1011  // update the blocks created by diamond codegen to point to the newly created phi
1012  // block
1013  cgen_state->ir_builder_.SetInsertPoint(null_check->cond_true_);
1014  cgen_state->ir_builder_.CreateBr(nullcheck_bb);
1015  cgen_state->ir_builder_.SetInsertPoint(null_check->cond_false_);
1016 }
1017 
1018 llvm::Value* CodeGenerator::NullCheckCodegen::finalize(llvm::Value* null_lv,
1019  llvm::Value* notnull_lv) {
1020  AUTOMATIC_IR_METADATA(cgen_state);
1021  CHECK(null_check);
1022  cgen_state->ir_builder_.CreateBr(nullcheck_bb);
1023 
1024  CHECK_EQ(null_lv->getType(), notnull_lv->getType());
1025 
1026  cgen_state->ir_builder_.SetInsertPoint(nullcheck_bb);
1027  nullcheck_value =
1028  cgen_state->ir_builder_.CreatePHI(null_lv->getType(), 2, name + "_value");
1029  nullcheck_value->addIncoming(notnull_lv, null_check->cond_false_);
1030  nullcheck_value->addIncoming(null_lv, null_check->cond_true_);
1031 
1032  null_check.reset(nullptr);
1033  cgen_state->ir_builder_.SetInsertPoint(nullcheck_bb);
1034  return nullcheck_value;
1035 }
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:660
#define CHECK_EQ(x, y)
Definition: Logger.h:205
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:984
#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:1152
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:825
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
bool is_fp() const
Definition: sqltypes.h:492
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:62
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:210
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
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:493
std::vector< llvm::Value * > codegenGeoBinOper(const Analyzer::GeoBinOper *, const CompilationOptions &)
Definition: GeoIR.cpp:86
bool is_time() const
Definition: sqltypes.h:494
std::shared_ptr< HashJoin > hash_table
Definition: Execute.h:841
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:168
std::vector< llvm::Value * > v_
#define INJECT_TIMER(DESC)
Definition: measure.h:93
#define CHECK_NE(x, y)
Definition: Logger.h:206
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
void setFalseTarget(llvm::BasicBlock *cond_false)
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)
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:207
const std::vector< InputTableInfo > & query_infos_
llvm::Function * filter_func_
Definition: CgenState.h:320
std::unique_ptr< GroupByAndAggregate::DiamondCodegen > null_check
#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:184
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:807
std::list< std::shared_ptr< Analyzer::Expr > > quals
llvm::Value * finalize(llvm::Value *null_lv, llvm::Value *notnull_lv)
Definition: IRCodegen.cpp:1018
#define CHECK(condition)
Definition: Logger.h:197
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
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, GroupByAndAggregate::DiamondCodegen &, std::stack< llvm::BasicBlock * > &, const bool thread_mem_shared)
Definition: IRCodegen.cpp:876
uint32_t log2_bytes(const uint32_t bytes)
Definition: Execute.h:178
std::string numeric_type_name(const SQLTypeInfo &ti)
Definition: Execute.h:211
void redeclareFilterFunction()
Definition: IRCodegen.cpp:709
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:601
Definition: sqldefs.h:39
SQLOps get_optype() const
Definition: Analyzer.h:370
#define VLOG(n)
Definition: Logger.h:291
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