OmniSciDB  a5dc49c757
 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 2022 HEAVY.AI, 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 
25 
26 // Driver methods for the IR generation.
27 
29 
30 std::vector<llvm::Value*> CodeGenerator::codegen(const Analyzer::Expr* expr,
31  const bool fetch_columns,
32  const CompilationOptions& co) {
34  if (!expr) {
35  return {posArg(expr)};
36  }
37  auto bin_oper = dynamic_cast<const Analyzer::BinOper*>(expr);
38  if (bin_oper) {
39  return {codegen(bin_oper, co)};
40  }
41  auto u_oper = dynamic_cast<const Analyzer::UOper*>(expr);
42  if (u_oper) {
43  return {codegen(u_oper, co)};
44  }
45  auto geo_col_var = dynamic_cast<const Analyzer::GeoColumnVar*>(expr);
46  if (geo_col_var) {
47  // inherits from ColumnVar, so it is important we check this first
48  return codegenGeoColumnVar(geo_col_var, fetch_columns, co);
49  }
50  auto col_var = dynamic_cast<const Analyzer::ColumnVar*>(expr);
51  if (col_var) {
52  return codegenColumn(col_var, fetch_columns, co);
53  }
54  auto constant = dynamic_cast<const Analyzer::Constant*>(expr);
55  if (constant) {
56  const auto& ti = constant->get_type_info();
57  if (ti.get_type() == kNULLT) {
58  throw std::runtime_error(
59  "NULL type literals are not currently supported in this context.");
60  }
61  if (constant->get_is_null()) {
62  const auto i8p_ty =
63  llvm::PointerType::get(get_int_type(8, executor_->cgen_state_->context_), 0);
64  if (ti.is_string() && ti.get_compression() == kENCODING_NONE) {
65  std::vector<llvm::Value*> null_target_lvs;
66  llvm::StructType* str_view_ty = createStringViewStructType();
67  auto null_str_view_struct_lv = cgen_state_->ir_builder_.CreateAlloca(str_view_ty);
68  // we do not need to fill the values of the string_view struct representing null
69  // string
70  null_target_lvs.push_back(
71  cgen_state_->ir_builder_.CreateLoad(str_view_ty, null_str_view_struct_lv));
72  null_target_lvs.push_back(llvm::ConstantPointerNull::get(
73  llvm::PointerType::get(llvm::IntegerType::get(cgen_state_->context_, 8), 0)));
74  null_target_lvs.push_back(cgen_state_->llInt((int32_t)0));
75  return null_target_lvs;
76  } else if (ti.is_geometry()) {
77  std::vector<llvm::Value*> ret_lvs;
78  // we classify whether the geo col value is null from the rhs of the left-join
79  // qual i.e., table S in the qual: R left join S on R.v = S.v by checking 1)
80  // nulled chunk_iter and 2) its col buffer w/ the size 0 for instance, we consider
81  // the size of col buffer for point as 16 and for other types we use `array_size`
82  // function to determine it, and they all assume valid geos have their buf size >
83  // 0 thus, by returning all bufs' ptr as nullptr we can return 0 as the length of
84  // the nulled geos' col val, and remaining logic can exploit this to finally
85  // return "null" as the col value of the corresponding row in the resultset
86  switch (ti.get_type()) {
87  // outer join's phi node in the generated code expects the # returned lvs'
88  // is the same as `col_ti.get_physical_coord_cols()`
89  // now we have necessary logic to deal with these nullptr and can conclude
90  // it as nulled geo val, i.e., see ResultSetIteration::991
91  case kPOINT:
92  case kMULTIPOINT:
93  case kLINESTRING:
94  return {llvm::ConstantPointerNull::get(i8p_ty)};
95  case kMULTILINESTRING:
96  case kPOLYGON:
97  return {llvm::ConstantPointerNull::get(i8p_ty),
98  llvm::ConstantPointerNull::get(i8p_ty)};
99  case kMULTIPOLYGON:
100  return {llvm::ConstantPointerNull::get(i8p_ty),
101  llvm::ConstantPointerNull::get(i8p_ty),
102  llvm::ConstantPointerNull::get(i8p_ty)};
103  default:
104  CHECK(false);
105  return {nullptr};
106  }
107  } else if (ti.is_array()) {
108  // similar to above nulled geo case, we can use this `nullptr` to guide
109  // `array_buff` and `array_size` functions representing nulled array value
110  return {llvm::ConstantPointerNull::get(i8p_ty)};
111  }
112  return {ti.is_fp()
113  ? static_cast<llvm::Value*>(executor_->cgen_state_->inlineFpNull(ti))
114  : static_cast<llvm::Value*>(executor_->cgen_state_->inlineIntNull(ti))};
115  }
116  if (ti.get_compression() == kENCODING_DICT) {
117  // The dictionary encoding case should be handled by the parent expression
118  // (cast, for now), here is too late to know the dictionary id if not already set
119  CHECK_NE(ti.getStringDictKey().dict_id, 0);
120  return {codegen(constant, ti.get_compression(), ti.getStringDictKey(), co)};
121  }
122  return {codegen(constant, ti.get_compression(), {}, co)};
123  }
124  auto case_expr = dynamic_cast<const Analyzer::CaseExpr*>(expr);
125  if (case_expr) {
126  return {codegen(case_expr, co)};
127  }
128  auto extract_expr = dynamic_cast<const Analyzer::ExtractExpr*>(expr);
129  if (extract_expr) {
130  return {codegen(extract_expr, co)};
131  }
132  auto dateadd_expr = dynamic_cast<const Analyzer::DateaddExpr*>(expr);
133  if (dateadd_expr) {
134  return {codegen(dateadd_expr, co)};
135  }
136  auto datediff_expr = dynamic_cast<const Analyzer::DatediffExpr*>(expr);
137  if (datediff_expr) {
138  return {codegen(datediff_expr, co)};
139  }
140  auto datetrunc_expr = dynamic_cast<const Analyzer::DatetruncExpr*>(expr);
141  if (datetrunc_expr) {
142  return {codegen(datetrunc_expr, co)};
143  }
144  auto charlength_expr = dynamic_cast<const Analyzer::CharLengthExpr*>(expr);
145  if (charlength_expr) {
146  return {codegen(charlength_expr, co)};
147  }
148  auto keyforstring_expr = dynamic_cast<const Analyzer::KeyForStringExpr*>(expr);
149  if (keyforstring_expr) {
150  return {codegen(keyforstring_expr, co)};
151  }
152  auto sample_ratio_expr = dynamic_cast<const Analyzer::SampleRatioExpr*>(expr);
153  if (sample_ratio_expr) {
154  return {codegen(sample_ratio_expr, co)};
155  }
156  auto string_oper_expr = dynamic_cast<const Analyzer::StringOper*>(expr);
157  if (string_oper_expr) {
158  return {codegen(string_oper_expr, co)};
159  }
160  auto cardinality_expr = dynamic_cast<const Analyzer::CardinalityExpr*>(expr);
161  if (cardinality_expr) {
162  return {codegen(cardinality_expr, co)};
163  }
164  auto like_expr = dynamic_cast<const Analyzer::LikeExpr*>(expr);
165  if (like_expr) {
166  return {codegen(like_expr, co)};
167  }
168  auto regexp_expr = dynamic_cast<const Analyzer::RegexpExpr*>(expr);
169  if (regexp_expr) {
170  return {codegen(regexp_expr, co)};
171  }
172  auto width_bucket_expr = dynamic_cast<const Analyzer::WidthBucketExpr*>(expr);
173  if (width_bucket_expr) {
174  return {codegen(width_bucket_expr, co)};
175  }
176 
177  auto ml_predict_expr = dynamic_cast<const Analyzer::MLPredictExpr*>(expr);
178  if (ml_predict_expr) {
179  return {codegen(ml_predict_expr, co)};
180  }
181 
182  auto pca_project_expr = dynamic_cast<const Analyzer::PCAProjectExpr*>(expr);
183  if (pca_project_expr) {
184  return {codegen(pca_project_expr, co)};
185  }
186 
187  auto likelihood_expr = dynamic_cast<const Analyzer::LikelihoodExpr*>(expr);
188  if (likelihood_expr) {
189  return {codegen(likelihood_expr->get_arg(), fetch_columns, co)};
190  }
191  auto in_expr = dynamic_cast<const Analyzer::InValues*>(expr);
192  if (in_expr) {
193  return {codegen(in_expr, co)};
194  }
195  auto in_integer_set_expr = dynamic_cast<const Analyzer::InIntegerSet*>(expr);
196  if (in_integer_set_expr) {
197  return {codegen(in_integer_set_expr, co)};
198  }
199  auto function_oper_with_custom_type_handling_expr =
200  dynamic_cast<const Analyzer::FunctionOperWithCustomTypeHandling*>(expr);
201  if (function_oper_with_custom_type_handling_expr) {
203  function_oper_with_custom_type_handling_expr, co)};
204  }
205  auto array_oper_expr = dynamic_cast<const Analyzer::ArrayExpr*>(expr);
206  if (array_oper_expr) {
207  return {codegenArrayExpr(array_oper_expr, co)};
208  }
209  auto geo_uop = dynamic_cast<const Analyzer::GeoUOper*>(expr);
210  if (geo_uop) {
211  return {codegenGeoUOper(geo_uop, co)};
212  }
213  auto geo_binop = dynamic_cast<const Analyzer::GeoBinOper*>(expr);
214  if (geo_binop) {
215  return {codegenGeoBinOper(geo_binop, co)};
216  }
217  auto function_oper_expr = dynamic_cast<const Analyzer::FunctionOper*>(expr);
218  if (function_oper_expr) {
219  return {codegenFunctionOper(function_oper_expr, co)};
220  }
221  auto geo_expr = dynamic_cast<const Analyzer::GeoExpr*>(expr);
222  if (geo_expr) {
223  return codegenGeoExpr(geo_expr, co);
224  }
225  if (dynamic_cast<const Analyzer::OffsetInFragment*>(expr)) {
226  return {posArg(nullptr)};
227  }
228  if (dynamic_cast<const Analyzer::WindowFunction*>(expr)) {
229  throw NativeExecutionError("Window expression not supported in this context");
230  }
231  abort();
232 }
233 
234 llvm::Value* CodeGenerator::codegen(const Analyzer::BinOper* bin_oper,
235  const CompilationOptions& co) {
237  const auto optype = bin_oper->get_optype();
238  if (IS_ARITHMETIC(optype)) {
239  return codegenArith(bin_oper, co);
240  }
241  if (IS_COMPARISON(optype)) {
242  return codegenCmp(bin_oper, co);
243  }
244  if (IS_LOGIC(optype)) {
245  return codegenLogical(bin_oper, co);
246  }
247  if (optype == kARRAY_AT) {
248  return codegenArrayAt(bin_oper, co);
249  }
250  abort();
251 }
252 
253 llvm::Value* CodeGenerator::codegen(const Analyzer::UOper* u_oper,
254  const CompilationOptions& co) {
256  const auto optype = u_oper->get_optype();
257  switch (optype) {
258  case kNOT: {
259  return codegenLogical(u_oper, co);
260  }
261  case kCAST: {
262  return codegenCast(u_oper, co);
263  }
264  case kUMINUS: {
265  return codegenUMinus(u_oper, co);
266  }
267  case kISNULL: {
268  return codegenIsNull(u_oper, co);
269  }
270  case kUNNEST:
271  return codegenUnnest(u_oper, co);
272  default:
273  UNREACHABLE();
274  }
275  return nullptr;
276 }
277 
279  const CompilationOptions& co) {
281  auto input_expr = expr->get_arg();
282  CHECK(input_expr);
283 
284  auto double_lv = codegen(input_expr, true, co);
285  CHECK_EQ(size_t(1), double_lv.size());
286 
287  std::unique_ptr<CodeGenerator::NullCheckCodegen> nullcheck_codegen;
288  const bool is_nullable = !input_expr->get_type_info().get_notnull();
289  if (is_nullable) {
290  nullcheck_codegen = std::make_unique<NullCheckCodegen>(cgen_state_,
291  executor(),
292  double_lv.front(),
293  input_expr->get_type_info(),
294  "sample_ratio_nullcheck");
295  }
296  CHECK_EQ(input_expr->get_type_info().get_type(), kDOUBLE);
297  std::vector<llvm::Value*> args{double_lv[0], posArg(nullptr)};
298  auto ret = cgen_state_->emitCall("sample_ratio", args);
299  if (nullcheck_codegen) {
300  ret = nullcheck_codegen->finalize(ll_bool(false, cgen_state_->context_), ret);
301  }
302  return ret;
303 }
304 
306  const CompilationOptions& co) {
308  auto target_value_expr = expr->get_target_value();
309  auto lower_bound_expr = expr->get_lower_bound();
310  auto upper_bound_expr = expr->get_upper_bound();
311  auto partition_count_expr = expr->get_partition_count();
312  CHECK(target_value_expr);
313  CHECK(lower_bound_expr);
314  CHECK(upper_bound_expr);
315  CHECK(partition_count_expr);
316 
317  auto is_constant_expr = [](const Analyzer::Expr* expr) {
318  auto target_expr = expr;
319  if (auto cast_expr = dynamic_cast<const Analyzer::UOper*>(expr)) {
320  if (cast_expr->get_optype() == SQLOps::kCAST) {
321  target_expr = cast_expr->get_operand();
322  }
323  }
324  // there are more complex constant expr like 1+2, 1/2*3, and so on
325  // but when considering a typical usage of width_bucket function
326  // it is sufficient to consider a singleton constant expr
327  auto constant_expr = dynamic_cast<const Analyzer::Constant*>(target_expr);
328  if (constant_expr) {
329  return true;
330  }
331  return false;
332  };
333  if (is_constant_expr(lower_bound_expr) && is_constant_expr(upper_bound_expr) &&
334  is_constant_expr(partition_count_expr)) {
335  expr->set_constant_expr();
336  }
337  // compute width_bucket's expresn range and check the possibility of avoiding oob check
338  auto col_range =
339  getExpressionRange(expr,
341  executor_,
342  boost::make_optional(plan_state_->getSimpleQuals()));
343  // check whether target_expr is valid
344  if (col_range.getType() == ExpressionRangeType::Integer &&
345  !expr->can_skip_out_of_bound_check() && col_range.getIntMin() > 0 &&
346  col_range.getIntMax() <= expr->get_partition_count_val()) {
347  // check whether target_col is not-nullable or has filter expr on it
348  if (!col_range.hasNulls()) {
349  // Even if the target_expr has its filter expression, target_col_range may exactly
350  // the same with the col_range of the target_expr's operand col,
351  // i.e., SELECT WIDTH_BUCKET(v1, 1, 10, 10) FROM T WHERE v1 != 1;
352  // In that query, col_range of v1 with/without considering the filter expression
353  // v1 != 1 have exactly the same col ranges, so we cannot recognize the existence
354  // of the filter expression based on them. Also, is (not) null is located in
355  // FilterNode, so we cannot trace it in here.
356  // todo (yoonmin): relax this to allow skipping oob check more cases
357  expr->skip_out_of_bound_check();
358  }
359  }
360  return expr->is_constant_expr() ? codegenConstantWidthBucketExpr(expr, co)
361  : codegenWidthBucketExpr(expr, co);
362 }
363 
365  const Analyzer::WidthBucketExpr* expr,
366  const CompilationOptions& co) {
367  auto target_value_expr = expr->get_target_value();
368  auto lower_bound_expr = expr->get_lower_bound();
369  auto upper_bound_expr = expr->get_upper_bound();
370  auto partition_count_expr = expr->get_partition_count();
371 
372  auto num_partitions = expr->get_partition_count_val();
373  if (num_partitions < 1 || num_partitions > INT32_MAX) {
374  throw std::runtime_error(
375  "PARTITION_COUNT expression of width_bucket function should be in a valid "
376  "range: 0 < PARTITION_COUNT <= 2147483647");
377  }
378  double lower = expr->get_bound_val(lower_bound_expr);
379  double upper = expr->get_bound_val(upper_bound_expr);
380  if (lower == upper) {
381  throw std::runtime_error(
382  "LOWER_BOUND and UPPER_BOUND expressions of width_bucket function cannot have "
383  "the same constant value");
384  }
385  if (lower == NULL_DOUBLE || upper == NULL_DOUBLE) {
386  throw std::runtime_error(
387  "Both LOWER_BOUND and UPPER_BOUND of width_bucket function should be finite "
388  "numeric constants.");
389  }
390 
391  bool const reversed = lower > upper;
392  double const scale_factor = num_partitions / (reversed ? lower - upper : upper - lower);
393  std::string func_name = reversed ? "width_bucket_reversed" : "width_bucket";
394 
395  auto get_double_constant_lvs = [this, &co](double const_val) {
396  Datum d;
397  d.doubleval = const_val;
398  auto double_const_expr =
399  makeExpr<Analyzer::Constant>(SQLTypeInfo(kDOUBLE, false), false, d);
400  return codegen(double_const_expr.get(), false, co);
401  };
402 
403  auto target_value_ti = target_value_expr->get_type_info();
404  auto target_value_expr_lvs = codegen(target_value_expr, true, co);
405  CHECK_EQ(size_t(1), target_value_expr_lvs.size());
406  auto lower_expr_lvs = codegen(lower_bound_expr, true, co);
407  CHECK_EQ(size_t(1), lower_expr_lvs.size());
408  auto scale_factor_lvs = get_double_constant_lvs(scale_factor);
409  CHECK_EQ(size_t(1), scale_factor_lvs.size());
410 
411  std::vector<llvm::Value*> width_bucket_args{target_value_expr_lvs[0],
412  lower_expr_lvs[0]};
413  if (expr->can_skip_out_of_bound_check()) {
414  func_name += "_no_oob_check";
415  width_bucket_args.push_back(scale_factor_lvs[0]);
416  } else {
417  auto upper_expr_lvs = codegen(upper_bound_expr, true, co);
418  CHECK_EQ(size_t(1), upper_expr_lvs.size());
419  auto partition_count_expr_lvs = codegen(partition_count_expr, true, co);
420  CHECK_EQ(size_t(1), partition_count_expr_lvs.size());
421  width_bucket_args.push_back(upper_expr_lvs[0]);
422  width_bucket_args.push_back(scale_factor_lvs[0]);
423  width_bucket_args.push_back(partition_count_expr_lvs[0]);
424  if (!target_value_ti.get_notnull()) {
425  func_name += "_nullable";
426  auto translated_null_value = target_value_ti.is_fp()
427  ? inline_fp_null_val(target_value_ti)
428  : inline_int_null_val(target_value_ti);
429  auto null_value_lvs = get_double_constant_lvs(translated_null_value);
430  CHECK_EQ(size_t(1), null_value_lvs.size());
431  width_bucket_args.push_back(null_value_lvs[0]);
432  }
433  }
434  return cgen_state_->emitCall(func_name, width_bucket_args);
435 }
436 
438  const CompilationOptions& co) {
439  auto target_value_expr = expr->get_target_value();
440  auto lower_bound_expr = expr->get_lower_bound();
441  auto upper_bound_expr = expr->get_upper_bound();
442  auto partition_count_expr = expr->get_partition_count();
443 
444  std::string func_name = "width_bucket_expr";
445  bool nullable_expr = false;
446  if (expr->can_skip_out_of_bound_check()) {
447  func_name += "_no_oob_check";
448  } else if (!target_value_expr->get_type_info().get_notnull()) {
449  func_name += "_nullable";
450  nullable_expr = true;
451  }
452 
453  auto target_value_expr_lvs = codegen(target_value_expr, true, co);
454  CHECK_EQ(size_t(1), target_value_expr_lvs.size());
455  auto lower_bound_expr_lvs = codegen(lower_bound_expr, true, co);
456  CHECK_EQ(size_t(1), lower_bound_expr_lvs.size());
457  auto upper_bound_expr_lvs = codegen(upper_bound_expr, true, co);
458  CHECK_EQ(size_t(1), upper_bound_expr_lvs.size());
459  auto partition_count_expr_lvs = codegen(partition_count_expr, true, co);
460  CHECK_EQ(size_t(1), partition_count_expr_lvs.size());
461  auto target_value_ti = target_value_expr->get_type_info();
462  auto null_value_lv = cgen_state_->inlineFpNull(target_value_ti);
463 
464  // check partition count : 1 ~ INT32_MAX
465  // INT32_MAX will be checked during casting by OVERFLOW checking step
466  auto partition_count_ti = partition_count_expr->get_type_info();
467  CHECK(partition_count_ti.is_integer());
468  auto int32_ti = SQLTypeInfo(kINT, partition_count_ti.get_notnull());
469  auto partition_count_expr_lv =
470  codegenCastBetweenIntTypes(partition_count_expr_lvs[0],
471  partition_count_ti,
472  int32_ti,
473  partition_count_ti.get_size() < int32_ti.get_size());
474  llvm::Value* chosen_min = cgen_state_->llInt(static_cast<int32_t>(0));
475  llvm::Value* partition_count_min =
476  cgen_state_->ir_builder_.CreateICmpSLE(partition_count_expr_lv, chosen_min);
477  llvm::BasicBlock* width_bucket_partition_count_ok_bb =
478  llvm::BasicBlock::Create(cgen_state_->context_,
479  "width_bucket_partition_count_ok_bb",
481  llvm::BasicBlock* width_bucket_argument_check_fail_bb =
482  llvm::BasicBlock::Create(cgen_state_->context_,
483  "width_bucket_argument_check_fail_bb",
485  cgen_state_->ir_builder_.CreateCondBr(partition_count_min,
486  width_bucket_argument_check_fail_bb,
487  width_bucket_partition_count_ok_bb);
488  cgen_state_->ir_builder_.SetInsertPoint(width_bucket_argument_check_fail_bb);
489  cgen_state_->ir_builder_.CreateRet(
490  cgen_state_->llInt(int32_t(heavyai::ErrorCode::WIDTH_BUCKET_INVALID_ARGUMENT)));
491  cgen_state_->ir_builder_.SetInsertPoint(width_bucket_partition_count_ok_bb);
492 
493  llvm::BasicBlock* width_bucket_bound_check_ok_bb =
494  llvm::BasicBlock::Create(cgen_state_->context_,
495  "width_bucket_bound_check_ok_bb",
497  llvm::Value* bound_check{nullptr};
498  if (lower_bound_expr->get_type_info().get_notnull() &&
499  upper_bound_expr->get_type_info().get_notnull()) {
500  bound_check = cgen_state_->ir_builder_.CreateFCmpOEQ(
501  lower_bound_expr_lvs[0], upper_bound_expr_lvs[0], "bound_check");
502  } else {
503  std::vector<llvm::Value*> bound_check_args{
504  lower_bound_expr_lvs[0],
505  upper_bound_expr_lvs[0],
506  null_value_lv,
507  cgen_state_->llInt(static_cast<int8_t>(1))};
508  bound_check = toBool(cgen_state_->emitCall("eq_double_nullable", bound_check_args));
509  }
510  cgen_state_->ir_builder_.CreateCondBr(
511  bound_check, width_bucket_argument_check_fail_bb, width_bucket_bound_check_ok_bb);
512  cgen_state_->ir_builder_.SetInsertPoint(width_bucket_bound_check_ok_bb);
514  auto reversed_expr = toBool(codegenCmp(SQLOps::kGT,
515  kONE,
516  lower_bound_expr_lvs,
517  lower_bound_expr->get_type_info(),
518  upper_bound_expr,
519  co));
520  auto lower_bound_expr_lv = lower_bound_expr_lvs[0];
521  auto upper_bound_expr_lv = upper_bound_expr_lvs[0];
522  std::vector<llvm::Value*> width_bucket_args{target_value_expr_lvs[0],
523  reversed_expr,
524  lower_bound_expr_lv,
525  upper_bound_expr_lv,
526  partition_count_expr_lv};
527  if (nullable_expr) {
528  width_bucket_args.push_back(null_value_lv);
529  }
530  return cgen_state_->emitCall(func_name, width_bucket_args);
531 }
532 
533 namespace {
534 
536  const std::shared_ptr<Analyzer::Expr>& qual) {
537  const auto qual_cf = qual_to_conjunctive_form(qual);
538  ra_exe_unit.simple_quals.insert(ra_exe_unit.simple_quals.end(),
539  qual_cf.simple_quals.begin(),
540  qual_cf.simple_quals.end());
541  ra_exe_unit.quals.insert(
542  ra_exe_unit.quals.end(), qual_cf.quals.begin(), qual_cf.quals.end());
543 }
544 
546  const ExecutionOptions& eo,
547  const std::vector<InputTableInfo>& query_infos,
548  const size_t level_idx,
549  const std::string& fail_reason) {
550  if (ra_exe_unit.input_descs.size() < 2) {
551  // We only support loop join at the end of folded joins
552  // where ra_exe_unit.input_descs.size() > 2 for now.
553  throw std::runtime_error("Hash join failed, reason(s): " + fail_reason +
554  " | Incorrect # tables for executing loop join");
555  }
556  const auto loop_join_size = get_loop_join_size(query_infos, ra_exe_unit);
557  const bool has_loop_size_hint =
559  const size_t loop_join_size_threshold =
560  has_loop_size_hint ? ra_exe_unit.query_hint.loop_join_inner_table_max_num_rows
562  if (eo.allow_loop_joins) {
563  if (has_loop_size_hint && loop_join_size_threshold < loop_join_size) {
564  throw std::runtime_error(
565  "Hash join failed, reason(s): " + fail_reason +
566  " | Cannot fall back to loop join for non-trivial inner table size");
567  }
568  return;
569  }
570  if (level_idx + 1 != ra_exe_unit.join_quals.size()) {
571  throw std::runtime_error(
572  "Hash join failed, reason(s): " + fail_reason +
573  " | Cannot fall back to loop join for intermediate join quals");
574  }
575  if (loop_join_size_threshold < loop_join_size) {
576  throw std::runtime_error(
577  "Hash join failed, reason(s): " + fail_reason +
578  " | Cannot fall back to loop join for non-trivial inner table size");
579  }
580  if (ra_exe_unit.query_hint.isHintRegistered(kDisableLoopJoin)) {
581  throw std::runtime_error("Hash join failed, reason(s): " + fail_reason +
582  " | Loop join is disabled by user");
583  }
584 }
585 
586 void check_valid_join_qual(std::shared_ptr<Analyzer::BinOper>& bin_oper) {
587  // check whether a join qual is valid before entering the hashtable build and codegen
588 
589  auto lhs_cv = dynamic_cast<const Analyzer::ColumnVar*>(bin_oper->get_left_operand());
590  auto rhs_cv = dynamic_cast<const Analyzer::ColumnVar*>(bin_oper->get_right_operand());
591  if (lhs_cv && rhs_cv && !bin_oper->is_bbox_intersect_oper()) {
592  auto lhs_type = lhs_cv->get_type_info().get_type();
593  auto rhs_type = rhs_cv->get_type_info().get_type();
594  // check #1. avoid a join btw full array columns
595  if (lhs_type == SQLTypes::kARRAY && rhs_type == SQLTypes::kARRAY) {
596  throw std::runtime_error(
597  "Join operation between full array columns (i.e., R.arr = S.arr) instead of "
598  "indexed array columns (i.e., R.arr[1] = S.arr[2]) is not supported yet.");
599  }
600  }
601  auto const lhs_et =
602  dynamic_cast<const Analyzer::ExpressionTuple*>(bin_oper->get_left_operand());
603  if (lhs_et) {
604  CHECK_LE(lhs_et->getTuple().size(), g_maximum_conditions_to_coalesce);
605  }
606 }
607 
608 } // namespace
609 
610 std::vector<JoinLoop> Executor::buildJoinLoops(
611  RelAlgExecutionUnit& ra_exe_unit,
612  const CompilationOptions& co,
613  const ExecutionOptions& eo,
614  const std::vector<InputTableInfo>& query_infos,
615  ColumnCacheMap& column_cache) {
616  INJECT_TIMER(buildJoinLoops);
618  std::vector<JoinLoop> join_loops;
619  for (size_t level_idx = 0, current_hash_table_idx = 0;
620  level_idx < ra_exe_unit.join_quals.size();
621  ++level_idx) {
622  const auto& current_level_join_conditions = ra_exe_unit.join_quals[level_idx];
623  std::vector<std::string> fail_reasons;
624  const auto current_level_hash_table =
625  buildCurrentLevelHashTable(current_level_join_conditions,
626  level_idx,
627  ra_exe_unit,
628  co,
629  query_infos,
630  column_cache,
631  fail_reasons);
632  const auto found_outer_join_matches_cb =
633  [this, level_idx](llvm::Value* found_outer_join_matches) {
637  found_outer_join_matches;
638  };
639  const auto is_deleted_cb = buildIsDeletedCb(ra_exe_unit, level_idx, co);
640  auto rem_left_join_quals_it =
642  bool has_remaining_left_join_quals =
643  rem_left_join_quals_it != plan_state_->left_join_non_hashtable_quals_.end() &&
644  !rem_left_join_quals_it->second.empty();
645  const auto outer_join_condition_remaining_quals_cb =
646  [this, level_idx, &co](const std::vector<llvm::Value*>& prev_iters) {
647  // when we have multiple quals for the left join in the current join level
648  // we first try to build a hashtable by using one of the possible qual,
649  // and deal with remaining quals as extra join conditions
650  FetchCacheAnchor anchor(cgen_state_.get());
651  addJoinLoopIterator(prev_iters, level_idx + 1);
652  llvm::Value* left_join_cond = cgen_state_->llBool(true);
653  CodeGenerator code_generator(this);
654  auto it = plan_state_->left_join_non_hashtable_quals_.find(level_idx);
655  if (it != plan_state_->left_join_non_hashtable_quals_.end()) {
656  for (auto expr : it->second) {
657  left_join_cond = cgen_state_->ir_builder_.CreateAnd(
658  left_join_cond,
659  code_generator.toBool(
660  code_generator.codegen(expr.get(), true, co).front()));
661  }
662  }
663  return left_join_cond;
664  };
665  if (current_level_hash_table) {
666  const auto hoisted_filters_cb = buildHoistLeftHandSideFiltersCb(
667  ra_exe_unit, level_idx, current_level_hash_table->getInnerTableId(), co);
668  if (current_level_hash_table->getHashType() == HashType::OneToOne) {
669  join_loops.emplace_back(
670  /*kind=*/JoinLoopKind::Singleton,
671  /*type=*/current_level_join_conditions.type,
672  /*iteration_domain_codegen=*/
673  [this, current_hash_table_idx, level_idx, current_level_hash_table, &co](
674  const std::vector<llvm::Value*>& prev_iters) {
675  addJoinLoopIterator(prev_iters, level_idx);
676  JoinLoopDomain domain{{0}};
677  domain.slot_lookup_result =
678  current_level_hash_table->codegenSlot(co, current_hash_table_idx);
679  return domain;
680  },
681  /*outer_condition_match=*/
682  current_level_join_conditions.type == JoinType::LEFT &&
683  has_remaining_left_join_quals
684  ? std::function<llvm::Value*(const std::vector<llvm::Value*>&)>(
685  outer_join_condition_remaining_quals_cb)
686  : nullptr,
687  /*found_outer_matches=*/current_level_join_conditions.type == JoinType::LEFT
688  ? std::function<void(llvm::Value*)>(found_outer_join_matches_cb)
689  : nullptr,
690  /*hoisted_filters=*/hoisted_filters_cb,
691  /*is_deleted=*/is_deleted_cb,
692  /*nested_loop_join=*/false);
693  } else if (auto range_join_table =
694  dynamic_cast<RangeJoinHashTable*>(current_level_hash_table.get())) {
695  join_loops.emplace_back(
696  /* kind= */ JoinLoopKind::MultiSet,
697  /* type= */ current_level_join_conditions.type,
698  /* iteration_domain_codegen= */
699  [this,
700  range_join_table,
701  current_hash_table_idx,
702  level_idx,
703  current_level_hash_table,
704  &co](const std::vector<llvm::Value*>& prev_iters) {
705  addJoinLoopIterator(prev_iters, level_idx);
706  JoinLoopDomain domain{{0}};
707  CHECK(!prev_iters.empty());
708  const auto matching_set = range_join_table->codegenMatchingSetWithOffset(
709  co, current_hash_table_idx, prev_iters.back());
710  domain.values_buffer = matching_set.elements;
711  domain.element_count = matching_set.count;
712  return domain;
713  },
714  /* outer_condition_match= */
715  current_level_join_conditions.type == JoinType::LEFT
716  ? std::function<llvm::Value*(const std::vector<llvm::Value*>&)>(
717  outer_join_condition_remaining_quals_cb)
718  : nullptr,
719  /* found_outer_matches= */
720  current_level_join_conditions.type == JoinType::LEFT
721  ? std::function<void(llvm::Value*)>(found_outer_join_matches_cb)
722  : nullptr,
723  /* hoisted_filters= */ nullptr, // <<! TODO
724  /* is_deleted= */ is_deleted_cb,
725  /*nested_loop_join=*/false);
726  } else {
727  join_loops.emplace_back(
728  /*kind=*/JoinLoopKind::Set,
729  /*type=*/current_level_join_conditions.type,
730  /*iteration_domain_codegen=*/
731  [this, current_hash_table_idx, level_idx, current_level_hash_table, &co](
732  const std::vector<llvm::Value*>& prev_iters) {
733  addJoinLoopIterator(prev_iters, level_idx);
734  JoinLoopDomain domain{{0}};
735  const auto matching_set = current_level_hash_table->codegenMatchingSet(
736  co, current_hash_table_idx);
737  domain.values_buffer = matching_set.elements;
738  domain.element_count = matching_set.count;
739  domain.error_code = matching_set.error_code;
740  return domain;
741  },
742  /*outer_condition_match=*/
743  current_level_join_conditions.type == JoinType::LEFT
744  ? std::function<llvm::Value*(const std::vector<llvm::Value*>&)>(
745  outer_join_condition_remaining_quals_cb)
746  : nullptr,
747  /*found_outer_matches=*/current_level_join_conditions.type == JoinType::LEFT
748  ? std::function<void(llvm::Value*)>(found_outer_join_matches_cb)
749  : nullptr,
750  /*hoisted_filters=*/hoisted_filters_cb,
751  /*is_deleted=*/is_deleted_cb,
752  /*nested_loop_join=*/false);
753  }
754  ++current_hash_table_idx;
755  } else {
756  const auto fail_reasons_str = current_level_join_conditions.quals.empty()
757  ? "No equijoin expression found"
758  : boost::algorithm::join(fail_reasons, " | ");
760  ra_exe_unit, eo, query_infos, level_idx, fail_reasons_str);
761  // Callback provided to the `JoinLoop` framework to evaluate the (outer) join
762  // condition.
763  VLOG(1) << "Unable to build hash table, falling back to loop join: "
764  << fail_reasons_str;
765  const auto outer_join_condition_cb =
766  [this, level_idx, &co, &current_level_join_conditions](
767  const std::vector<llvm::Value*>& prev_iters) {
768  // The values generated for the match path don't dominate all uses
769  // since on the non-match path nulls are generated. Reset the cache
770  // once the condition is generated to avoid incorrect reuse.
771  FetchCacheAnchor anchor(cgen_state_.get());
772  addJoinLoopIterator(prev_iters, level_idx + 1);
773  llvm::Value* left_join_cond = cgen_state_->llBool(true);
774  CodeGenerator code_generator(this);
775  for (auto expr : current_level_join_conditions.quals) {
776  left_join_cond = cgen_state_->ir_builder_.CreateAnd(
777  left_join_cond,
778  code_generator.toBool(
779  code_generator.codegen(expr.get(), true, co).front()));
780  }
781  return left_join_cond;
782  };
783  join_loops.emplace_back(
784  /*kind=*/JoinLoopKind::UpperBound,
785  /*type=*/current_level_join_conditions.type,
786  /*iteration_domain_codegen=*/
787  [this, level_idx](const std::vector<llvm::Value*>& prev_iters) {
788  addJoinLoopIterator(prev_iters, level_idx);
789  JoinLoopDomain domain{{0}};
790  auto* arg = get_arg_by_name(cgen_state_->row_func_, "num_rows_per_scan");
791  const auto rows_per_scan_ptr = cgen_state_->ir_builder_.CreateGEP(
792  arg->getType()->getScalarType()->getPointerElementType(),
793  arg,
794  cgen_state_->llInt(int32_t(level_idx + 1)));
795  domain.upper_bound = cgen_state_->ir_builder_.CreateLoad(
796  rows_per_scan_ptr->getType()->getPointerElementType(),
797  rows_per_scan_ptr,
798  "num_rows_per_scan");
799  return domain;
800  },
801  /*outer_condition_match=*/
802  current_level_join_conditions.type == JoinType::LEFT
803  ? std::function<llvm::Value*(const std::vector<llvm::Value*>&)>(
804  outer_join_condition_cb)
805  : nullptr,
806  /*found_outer_matches=*/
807  current_level_join_conditions.type == JoinType::LEFT
808  ? std::function<void(llvm::Value*)>(found_outer_join_matches_cb)
809  : nullptr,
810  /*hoisted_filters=*/nullptr,
811  /*is_deleted=*/is_deleted_cb,
812  /*nested_loop_join=*/true);
813  }
814  }
815  return join_loops;
816 }
817 
818 namespace {
819 
820 class ExprTableIdVisitor : public ScalarExprVisitor<std::set<shared::TableKey>> {
821  protected:
822  std::set<shared::TableKey> visitColumnVar(
823  const Analyzer::ColumnVar* col_expr) const final {
824  return {col_expr->getTableKey()};
825  }
826 
827  std::set<shared::TableKey> visitFunctionOper(
828  const Analyzer::FunctionOper* func_expr) const final {
829  std::set<shared::TableKey> ret;
830  for (size_t i = 0; i < func_expr->getArity(); i++) {
831  ret = aggregateResult(ret, visit(func_expr->getArg(i)));
832  }
833  return ret;
834  }
835 
836  std::set<shared::TableKey> visitBinOper(const Analyzer::BinOper* bin_oper) const final {
837  std::set<shared::TableKey> ret;
838  ret = aggregateResult(ret, visit(bin_oper->get_left_operand()));
839  return aggregateResult(ret, visit(bin_oper->get_right_operand()));
840  }
841 
842  std::set<shared::TableKey> visitUOper(const Analyzer::UOper* u_oper) const final {
843  return visit(u_oper->get_operand());
844  }
845 
846  std::set<shared::TableKey> aggregateResult(
847  const std::set<shared::TableKey>& aggregate,
848  const std::set<shared::TableKey>& next_result) const final {
849  auto ret = aggregate; // copy
850  for (const auto& el : next_result) {
851  ret.insert(el);
852  }
853  return ret;
854  }
855 };
856 
857 } // namespace
858 
860  const RelAlgExecutionUnit& ra_exe_unit,
861  const size_t level_idx,
862  const shared::TableKey& inner_table_id,
863  const CompilationOptions& co) {
865  return nullptr;
866  }
867 
868  const auto& current_level_join_conditions = ra_exe_unit.join_quals[level_idx];
869  if (level_idx == 0 && current_level_join_conditions.type == JoinType::LEFT) {
870  const auto& condition = current_level_join_conditions.quals.front();
871  const auto bin_oper = dynamic_cast<const Analyzer::BinOper*>(condition.get());
872  CHECK(bin_oper) << condition->toString();
873  const auto rhs =
874  dynamic_cast<const Analyzer::ColumnVar*>(bin_oper->get_right_operand());
875  const auto lhs =
876  dynamic_cast<const Analyzer::ColumnVar*>(bin_oper->get_left_operand());
877  if (lhs && rhs && lhs->getTableKey() != rhs->getTableKey()) {
878  const Analyzer::ColumnVar* selected_lhs{nullptr};
879  // grab the left hand side column -- this is somewhat similar to normalize column
880  // pair, and a better solution may be to hoist that function out of the join
881  // framework and normalize columns at the top of build join loops
882  if (lhs->getTableKey() == inner_table_id) {
883  selected_lhs = rhs;
884  } else if (rhs->getTableKey() == inner_table_id) {
885  selected_lhs = lhs;
886  }
887  if (selected_lhs) {
888  std::list<std::shared_ptr<Analyzer::Expr>> hoisted_quals;
889  // get all LHS-only filters
890  auto should_hoist_qual = [&hoisted_quals](const auto& qual,
891  const shared::TableKey& table_key) {
892  CHECK(qual);
893 
894  ExprTableIdVisitor visitor;
895  const auto table_keys = visitor.visit(qual.get());
896  if (table_keys.size() == 1 && table_keys.find(table_key) != table_keys.end()) {
897  hoisted_quals.push_back(qual);
898  }
899  };
900  for (const auto& qual : ra_exe_unit.simple_quals) {
901  should_hoist_qual(qual, selected_lhs->getTableKey());
902  }
903  for (const auto& qual : ra_exe_unit.quals) {
904  should_hoist_qual(qual, selected_lhs->getTableKey());
905  }
906 
907  // build the filters callback and return it
908  if (!hoisted_quals.empty()) {
909  return [this, hoisted_quals, co](llvm::BasicBlock* true_bb,
910  llvm::BasicBlock* exit_bb,
911  const std::string& loop_name,
912  llvm::Function* parent_func,
913  CgenState* cgen_state) -> llvm::BasicBlock* {
914  // make sure we have quals to hoist
915  bool has_quals_to_hoist = false;
916  for (const auto& qual : hoisted_quals) {
917  // check to see if the filter was previously hoisted. if all filters were
918  // previously hoisted, this callback becomes a noop
919  if (plan_state_->hoisted_filters_.count(qual) == 0) {
920  has_quals_to_hoist = true;
921  break;
922  }
923  }
924 
925  if (!has_quals_to_hoist) {
926  return nullptr;
927  }
928 
929  AUTOMATIC_IR_METADATA(cgen_state);
930 
931  llvm::IRBuilder<>& builder = cgen_state->ir_builder_;
932  auto& context = builder.getContext();
933 
934  const auto filter_bb =
935  llvm::BasicBlock::Create(context,
936  "hoisted_left_join_filters_" + loop_name,
937  parent_func,
938  /*insert_before=*/true_bb);
939  builder.SetInsertPoint(filter_bb);
940 
941  llvm::Value* filter_lv = cgen_state_->llBool(true);
942  CodeGenerator code_generator(this);
943  CHECK(plan_state_);
944  for (const auto& qual : hoisted_quals) {
945  if (plan_state_->hoisted_filters_.insert(qual).second) {
946  // qual was inserted into the hoisted filters map, which means we have not
947  // seen this qual before. Generate filter.
948  VLOG(1) << "Generating code for hoisted left hand side qualifier "
949  << qual->toString();
950  auto cond = code_generator.toBool(
951  code_generator.codegen(qual.get(), true, co).front());
952  filter_lv = builder.CreateAnd(filter_lv, cond);
953  }
954  }
955  CHECK(filter_lv->getType()->isIntegerTy(1));
956 
957  builder.CreateCondBr(filter_lv, true_bb, exit_bb);
958  return filter_bb;
959  };
960  }
961  }
962  }
963  }
964  return nullptr;
965 }
966 
967 std::function<llvm::Value*(const std::vector<llvm::Value*>&, llvm::Value*)>
969  const size_t level_idx,
970  const CompilationOptions& co) {
971  AUTOMATIC_IR_METADATA(cgen_state_.get());
972  if (!co.filter_on_deleted_column) {
973  return nullptr;
974  }
975  CHECK_LT(level_idx + 1, ra_exe_unit.input_descs.size());
976  const auto input_desc = ra_exe_unit.input_descs[level_idx + 1];
977  if (input_desc.getSourceType() != InputSourceType::TABLE) {
978  return nullptr;
979  }
980 
981  const auto deleted_cd = plan_state_->getDeletedColForTable(input_desc.getTableKey());
982  if (!deleted_cd) {
983  return nullptr;
984  }
985  CHECK(deleted_cd->columnType.is_boolean());
986  const auto deleted_expr = makeExpr<Analyzer::ColumnVar>(
987  deleted_cd->columnType,
988  shared::ColumnKey{input_desc.getTableKey(), deleted_cd->columnId},
989  input_desc.getNestLevel());
990  return [this, deleted_expr, level_idx, &co](const std::vector<llvm::Value*>& prev_iters,
991  llvm::Value* have_more_inner_rows) {
992  const auto matching_row_index = addJoinLoopIterator(prev_iters, level_idx + 1);
993  // Avoid fetching the deleted column from a position which is not valid.
994  // An invalid position can be returned by a one to one hash lookup (negative)
995  // or at the end of iteration over a set of matching values.
996  llvm::Value* is_valid_it{nullptr};
997  if (have_more_inner_rows) {
998  is_valid_it = have_more_inner_rows;
999  } else {
1000  is_valid_it = cgen_state_->ir_builder_.CreateICmp(
1001  llvm::ICmpInst::ICMP_SGE, matching_row_index, cgen_state_->llInt<int64_t>(0));
1002  }
1003  const auto it_valid_bb = llvm::BasicBlock::Create(
1004  cgen_state_->context_, "it_valid", cgen_state_->current_func_);
1005  const auto it_not_valid_bb = llvm::BasicBlock::Create(
1006  cgen_state_->context_, "it_not_valid", cgen_state_->current_func_);
1007  cgen_state_->ir_builder_.CreateCondBr(is_valid_it, it_valid_bb, it_not_valid_bb);
1008  const auto row_is_deleted_bb = llvm::BasicBlock::Create(
1009  cgen_state_->context_, "row_is_deleted", cgen_state_->current_func_);
1010  cgen_state_->ir_builder_.SetInsertPoint(it_valid_bb);
1011  CodeGenerator code_generator(this);
1012  const auto row_is_deleted = code_generator.toBool(
1013  code_generator.codegen(deleted_expr.get(), true, co).front());
1014  cgen_state_->ir_builder_.CreateBr(row_is_deleted_bb);
1015  cgen_state_->ir_builder_.SetInsertPoint(it_not_valid_bb);
1016  const auto row_is_deleted_default = cgen_state_->llBool(false);
1017  cgen_state_->ir_builder_.CreateBr(row_is_deleted_bb);
1018  cgen_state_->ir_builder_.SetInsertPoint(row_is_deleted_bb);
1019  auto row_is_deleted_or_default =
1020  cgen_state_->ir_builder_.CreatePHI(row_is_deleted->getType(), 2);
1021  row_is_deleted_or_default->addIncoming(row_is_deleted, it_valid_bb);
1022  row_is_deleted_or_default->addIncoming(row_is_deleted_default, it_not_valid_bb);
1023  return row_is_deleted_or_default;
1024  };
1025 }
1026 
1027 std::shared_ptr<HashJoin> Executor::buildCurrentLevelHashTable(
1028  const JoinCondition& current_level_join_conditions,
1029  size_t level_idx,
1030  RelAlgExecutionUnit& ra_exe_unit,
1031  const CompilationOptions& co,
1032  const std::vector<InputTableInfo>& query_infos,
1033  ColumnCacheMap& column_cache,
1034  std::vector<std::string>& fail_reasons) {
1035  AUTOMATIC_IR_METADATA(cgen_state_.get());
1036  std::shared_ptr<HashJoin> current_level_hash_table;
1037  auto handleNonHashtableQual = [&ra_exe_unit, &level_idx, this](
1038  JoinType join_type,
1039  std::shared_ptr<Analyzer::Expr> qual) {
1040  if (join_type == JoinType::LEFT) {
1041  plan_state_->addNonHashtableQualForLeftJoin(level_idx, qual);
1042  } else {
1043  add_qualifier_to_execution_unit(ra_exe_unit, qual);
1044  }
1045  };
1046  for (const auto& join_qual : current_level_join_conditions.quals) {
1047  auto qual_bin_oper = std::dynamic_pointer_cast<Analyzer::BinOper>(join_qual);
1048  if (current_level_hash_table || !qual_bin_oper ||
1049  !IS_EQUIVALENCE(qual_bin_oper->get_optype())) {
1050  handleNonHashtableQual(current_level_join_conditions.type, join_qual);
1051  if (!current_level_hash_table) {
1052  fail_reasons.emplace_back("No equijoin expression found");
1053  }
1054  continue;
1055  }
1056  check_valid_join_qual(qual_bin_oper);
1057  JoinHashTableOrError hash_table_or_error;
1058  if (!current_level_hash_table) {
1059  hash_table_or_error = buildHashTableForQualifier(
1060  qual_bin_oper,
1061  query_infos,
1064  current_level_join_conditions.type,
1066  column_cache,
1067  ra_exe_unit.hash_table_build_plan_dag,
1068  ra_exe_unit.query_hint,
1069  ra_exe_unit.table_id_to_node_map);
1070  current_level_hash_table = hash_table_or_error.hash_table;
1071  }
1072  if (hash_table_or_error.hash_table) {
1073  plan_state_->join_info_.join_hash_tables_.push_back(hash_table_or_error.hash_table);
1074  plan_state_->join_info_.equi_join_tautologies_.push_back(qual_bin_oper);
1075  } else {
1076  fail_reasons.push_back(hash_table_or_error.fail_reason);
1077  if (!current_level_hash_table) {
1078  VLOG(2) << "Building a hashtable based on a qual " << qual_bin_oper->toString()
1079  << " fails: " << hash_table_or_error.fail_reason;
1080  }
1081  handleNonHashtableQual(current_level_join_conditions.type, qual_bin_oper);
1082  }
1083  }
1084  return current_level_hash_table;
1085 }
1086 
1088  if (!cgen_state_->filter_func_) {
1089  return;
1090  }
1091 
1092  // Loop over all the instructions used in the filter func.
1093  // The filter func instructions were generated as if for row func.
1094  // Remap any values used by those instructions to filter func args
1095  // and remember to forward them through the call in the row func.
1096  for (auto bb_it = cgen_state_->filter_func_->begin();
1097  bb_it != cgen_state_->filter_func_->end();
1098  ++bb_it) {
1099  for (auto instr_it = bb_it->begin(); instr_it != bb_it->end(); ++instr_it) {
1100  size_t i = 0;
1101  for (auto op_it = instr_it->value_op_begin(); op_it != instr_it->value_op_end();
1102  ++op_it, ++i) {
1103  llvm::Value* v = *op_it;
1104 
1105  // The last LLVM operand on a call instruction is the function to be called. Never
1106  // remap it.
1107  if (llvm::dyn_cast<const llvm::CallInst>(instr_it) &&
1108  op_it == instr_it->value_op_end() - 1) {
1109  continue;
1110  }
1111 
1112  CHECK(v);
1113  if (auto* instr = llvm::dyn_cast<llvm::Instruction>(v);
1114  instr && instr->getParent() &&
1115  instr->getParent()->getParent() == cgen_state_->row_func_) {
1116  // Remember that this filter func arg is needed.
1117  cgen_state_->filter_func_args_[v] = nullptr;
1118  } else if (auto* argum = llvm::dyn_cast<llvm::Argument>(v);
1119  argum && argum->getParent() == cgen_state_->row_func_) {
1120  // Remember that this filter func arg is needed.
1121  cgen_state_->filter_func_args_[v] = nullptr;
1122  }
1123  }
1124  }
1125  }
1126 
1127  // Create filter_func2 with parameters only for those row func values that are known to
1128  // be used in the filter func code.
1129  std::vector<llvm::Type*> filter_func_arg_types;
1130  filter_func_arg_types.reserve(cgen_state_->filter_func_args_.v_.size());
1131  for (auto& arg : cgen_state_->filter_func_args_.v_) {
1132  filter_func_arg_types.push_back(arg->getType());
1133  }
1134  auto ft = llvm::FunctionType::get(
1135  get_int_type(32, cgen_state_->context_), filter_func_arg_types, false);
1136  cgen_state_->filter_func_->setName("old_filter_func");
1137  auto filter_func2 = llvm::Function::Create(ft,
1138  llvm::Function::ExternalLinkage,
1139  "filter_func",
1140  cgen_state_->filter_func_->getParent());
1141  CHECK_EQ(filter_func2->arg_size(), cgen_state_->filter_func_args_.v_.size());
1142  auto arg_it = cgen_state_->filter_func_args_.begin();
1143  size_t i = 0;
1144  for (llvm::Function::arg_iterator I = filter_func2->arg_begin(),
1145  E = filter_func2->arg_end();
1146  I != E;
1147  ++I, ++arg_it) {
1148  arg_it->second = &*I;
1149  if (arg_it->first->hasName()) {
1150  I->setName(arg_it->first->getName());
1151  } else {
1152  I->setName("extra" + std::to_string(i++));
1153  }
1154  }
1155 
1156  // copy the filter_func function body over
1157  // see
1158  // https://stackoverflow.com/questions/12864106/move-function-body-avoiding-full-cloning/18751365
1159  filter_func2->getBasicBlockList().splice(
1160  filter_func2->begin(), cgen_state_->filter_func_->getBasicBlockList());
1161 
1162  if (cgen_state_->current_func_ == cgen_state_->filter_func_) {
1163  cgen_state_->current_func_ = filter_func2;
1164  }
1165  cgen_state_->filter_func_ = filter_func2;
1166 
1167  // loop over all the operands in the filter func
1168  for (auto bb_it = cgen_state_->filter_func_->begin();
1169  bb_it != cgen_state_->filter_func_->end();
1170  ++bb_it) {
1171  for (auto instr_it = bb_it->begin(); instr_it != bb_it->end(); ++instr_it) {
1172  size_t i = 0;
1173  for (auto op_it = instr_it->op_begin(); op_it != instr_it->op_end(); ++op_it, ++i) {
1174  llvm::Value* v = op_it->get();
1175  if (auto arg_it = cgen_state_->filter_func_args_.find(v);
1176  arg_it != cgen_state_->filter_func_args_.end()) {
1177  // replace row func value with a filter func arg
1178  llvm::Use* use = &*op_it;
1179  use->set(arg_it->second);
1180  }
1181  }
1182  }
1183  }
1184 }
1185 
1186 llvm::Value* Executor::addJoinLoopIterator(const std::vector<llvm::Value*>& prev_iters,
1187  const size_t level_idx) {
1188  AUTOMATIC_IR_METADATA(cgen_state_.get());
1189  // Iterators are added for loop-outer joins when the head of the loop is generated,
1190  // then once again when the body if generated. Allow this instead of special handling
1191  // of call sites.
1192  const auto it = cgen_state_->scan_idx_to_hash_pos_.find(level_idx);
1193  if (it != cgen_state_->scan_idx_to_hash_pos_.end()) {
1194  return it->second;
1195  }
1196  CHECK(!prev_iters.empty());
1197  llvm::Value* matching_row_index = prev_iters.back();
1198  const auto it_ok =
1199  cgen_state_->scan_idx_to_hash_pos_.emplace(level_idx, matching_row_index);
1200  CHECK(it_ok.second);
1201  return matching_row_index;
1202 }
1203 
1204 void Executor::codegenJoinLoops(const std::vector<JoinLoop>& join_loops,
1205  const RelAlgExecutionUnit& ra_exe_unit,
1206  GroupByAndAggregate& group_by_and_aggregate,
1207  llvm::Function* query_func,
1208  llvm::BasicBlock* entry_bb,
1210  const CompilationOptions& co,
1211  const ExecutionOptions& eo) {
1212  AUTOMATIC_IR_METADATA(cgen_state_.get());
1213  const auto exit_bb =
1214  llvm::BasicBlock::Create(cgen_state_->context_, "exit", cgen_state_->current_func_);
1215  cgen_state_->ir_builder_.SetInsertPoint(exit_bb);
1216  cgen_state_->ir_builder_.CreateRet(cgen_state_->llInt<int32_t>(0));
1217  cgen_state_->ir_builder_.SetInsertPoint(entry_bb);
1218  CodeGenerator code_generator(this);
1219 
1220  llvm::BasicBlock* loops_entry_bb{nullptr};
1221  auto has_range_join =
1222  std::any_of(join_loops.begin(), join_loops.end(), [](const auto& join_loop) {
1223  return join_loop.kind() == JoinLoopKind::MultiSet;
1224  });
1225  if (has_range_join) {
1226  CHECK_EQ(join_loops.size(), size_t(1));
1227  const auto element_count =
1228  llvm::ConstantInt::get(get_int_type(64, cgen_state_->context_), 9);
1229 
1230  auto compute_packed_offset = [](const int32_t x, const int32_t y) -> uint64_t {
1231  const uint64_t y_shifted = static_cast<uint64_t>(y) << 32;
1232  return y_shifted | static_cast<uint32_t>(x);
1233  };
1234 
1235  const auto values_arr = std::vector<llvm::Constant*>{
1236  llvm::ConstantInt::get(get_int_type(64, cgen_state_->context_), 0),
1237  llvm::ConstantInt::get(get_int_type(64, cgen_state_->context_),
1238  compute_packed_offset(0, 1)),
1239  llvm::ConstantInt::get(get_int_type(64, cgen_state_->context_),
1240  compute_packed_offset(0, -1)),
1241  llvm::ConstantInt::get(get_int_type(64, cgen_state_->context_),
1242  compute_packed_offset(1, 0)),
1243  llvm::ConstantInt::get(get_int_type(64, cgen_state_->context_),
1244  compute_packed_offset(1, 1)),
1245  llvm::ConstantInt::get(get_int_type(64, cgen_state_->context_),
1246  compute_packed_offset(1, -1)),
1247  llvm::ConstantInt::get(get_int_type(64, cgen_state_->context_),
1248  compute_packed_offset(-1, 0)),
1249  llvm::ConstantInt::get(get_int_type(64, cgen_state_->context_),
1250  compute_packed_offset(-1, 1)),
1251  llvm::ConstantInt::get(get_int_type(64, cgen_state_->context_),
1252  compute_packed_offset(-1, -1))};
1253 
1254  const auto constant_values_array = llvm::ConstantArray::get(
1255  get_int_array_type(64, 9, cgen_state_->context_), values_arr);
1256  CHECK(cgen_state_->module_);
1257  const auto values =
1258  new llvm::GlobalVariable(*cgen_state_->module_,
1259  get_int_array_type(64, 9, cgen_state_->context_),
1260  true,
1261  llvm::GlobalValue::LinkageTypes::InternalLinkage,
1262  constant_values_array);
1263  JoinLoop join_loop(
1266  [element_count, values](const std::vector<llvm::Value*>& v) {
1267  JoinLoopDomain domain{{0}};
1268  domain.element_count = element_count;
1269  domain.values_buffer = values;
1270  return domain;
1271  },
1272  nullptr,
1273  nullptr,
1274  nullptr,
1275  nullptr,
1276  "range_key_loop");
1277 
1278  loops_entry_bb = JoinLoop::codegen(
1279  {join_loop},
1280  [this,
1281  query_func,
1282  &query_mem_desc,
1283  &co,
1284  &eo,
1285  &group_by_and_aggregate,
1286  &join_loops,
1287  &ra_exe_unit](const std::vector<llvm::Value*>& prev_iters) {
1288  auto& builder = cgen_state_->ir_builder_;
1289 
1290  auto body_exit_bb =
1291  llvm::BasicBlock::Create(cgen_state_->context_,
1292  "range_key_inner_body_exit",
1293  builder.GetInsertBlock()->getParent());
1294 
1295  auto range_key_body_bb =
1296  llvm::BasicBlock::Create(cgen_state_->context_,
1297  "range_key_loop_body",
1298  builder.GetInsertBlock()->getParent());
1299  builder.SetInsertPoint(range_key_body_bb);
1300 
1301  const auto body_loops_entry_bb = JoinLoop::codegen(
1302  join_loops,
1303  [this,
1304  query_func,
1305  &query_mem_desc,
1306  &co,
1307  &eo,
1308  &group_by_and_aggregate,
1309  &join_loops,
1310  &ra_exe_unit](const std::vector<llvm::Value*>& prev_iters) {
1311  addJoinLoopIterator(prev_iters, join_loops.size());
1312  auto& builder = cgen_state_->ir_builder_;
1313  const auto loop_body_bb =
1314  llvm::BasicBlock::Create(builder.getContext(),
1315  "loop_body",
1316  builder.GetInsertBlock()->getParent());
1317  builder.SetInsertPoint(loop_body_bb);
1318  const bool can_return_error =
1319  compileBody(ra_exe_unit, group_by_and_aggregate, query_mem_desc, co);
1320  if (can_return_error || cgen_state_->needs_error_check_ ||
1321  eo.with_dynamic_watchdog || eo.allow_runtime_query_interrupt) {
1322  createErrorCheckControlFlow(query_func,
1323  eo.with_dynamic_watchdog,
1324  eo.allow_runtime_query_interrupt,
1325  join_loops,
1326  co.device_type,
1327  group_by_and_aggregate.query_infos_);
1328  }
1329  return loop_body_bb;
1330  },
1331  prev_iters.back(),
1332  body_exit_bb,
1333  cgen_state_.get());
1334 
1335  builder.SetInsertPoint(range_key_body_bb);
1336  cgen_state_->ir_builder_.CreateBr(body_loops_entry_bb);
1337 
1338  builder.SetInsertPoint(body_exit_bb);
1339  return range_key_body_bb;
1340  },
1341  code_generator.posArg(nullptr),
1342  exit_bb,
1343  cgen_state_.get());
1344  } else {
1345  loops_entry_bb = JoinLoop::codegen(
1346  join_loops,
1347  /*body_codegen=*/
1348  [this,
1349  query_func,
1350  &query_mem_desc,
1351  &co,
1352  &eo,
1353  &group_by_and_aggregate,
1354  &join_loops,
1355  &ra_exe_unit](const std::vector<llvm::Value*>& prev_iters) {
1356  AUTOMATIC_IR_METADATA(cgen_state_.get());
1357  addJoinLoopIterator(prev_iters, join_loops.size());
1358  auto& builder = cgen_state_->ir_builder_;
1359  const auto loop_body_bb = llvm::BasicBlock::Create(
1360  builder.getContext(), "loop_body", builder.GetInsertBlock()->getParent());
1361  builder.SetInsertPoint(loop_body_bb);
1362  const bool can_return_error =
1363  compileBody(ra_exe_unit, group_by_and_aggregate, query_mem_desc, co);
1364  if (can_return_error || cgen_state_->needs_error_check_ ||
1366  createErrorCheckControlFlow(query_func,
1369  join_loops,
1370  co.device_type,
1371  group_by_and_aggregate.query_infos_);
1372  }
1373  return loop_body_bb;
1374  },
1375  /*outer_iter=*/code_generator.posArg(nullptr),
1376  exit_bb,
1377  cgen_state_.get());
1378  }
1379  CHECK(loops_entry_bb);
1380  cgen_state_->ir_builder_.SetInsertPoint(entry_bb);
1381  cgen_state_->ir_builder_.CreateBr(loops_entry_bb);
1382 }
1383 
1385  Analyzer::Expr* group_by_col,
1386  const size_t col_width,
1387  const CompilationOptions& co,
1388  const bool translate_null_val,
1389  const int64_t translated_null_val,
1390  DiamondCodegen& diamond_codegen,
1391  std::stack<llvm::BasicBlock*>& array_loops,
1392  const bool thread_mem_shared) {
1393  AUTOMATIC_IR_METADATA(cgen_state_.get());
1394  CHECK_GE(col_width, sizeof(int32_t));
1395  CodeGenerator code_generator(this);
1396  auto group_key = code_generator.codegen(group_by_col, true, co).front();
1397  auto key_to_cache = group_key;
1398  if (dynamic_cast<Analyzer::UOper*>(group_by_col) &&
1399  static_cast<Analyzer::UOper*>(group_by_col)->get_optype() == kUNNEST) {
1400  auto preheader = cgen_state_->ir_builder_.GetInsertBlock();
1401  auto array_loop_head = llvm::BasicBlock::Create(cgen_state_->context_,
1402  "array_loop_head",
1403  cgen_state_->current_func_,
1404  preheader->getNextNode());
1405  diamond_codegen.setFalseTarget(array_loop_head);
1406  const auto ret_ty = get_int_type(32, cgen_state_->context_);
1407  auto array_idx_ptr = cgen_state_->ir_builder_.CreateAlloca(ret_ty);
1408  CHECK(array_idx_ptr);
1409  cgen_state_->ir_builder_.CreateStore(cgen_state_->llInt(int32_t(0)), array_idx_ptr);
1410  const auto arr_expr = static_cast<Analyzer::UOper*>(group_by_col)->get_operand();
1411  const auto& array_ti = arr_expr->get_type_info();
1412  CHECK(array_ti.is_array());
1413  const auto& elem_ti = array_ti.get_elem_type();
1414  auto array_len =
1415  (array_ti.get_size() > 0)
1416  ? cgen_state_->llInt(array_ti.get_size() / elem_ti.get_size())
1417  : cgen_state_->emitExternalCall(
1418  "array_size",
1419  ret_ty,
1420  {group_key,
1421  code_generator.posArg(arr_expr),
1422  cgen_state_->llInt(log2_bytes(elem_ti.get_logical_size()))});
1423  cgen_state_->ir_builder_.CreateBr(array_loop_head);
1424  cgen_state_->ir_builder_.SetInsertPoint(array_loop_head);
1425  CHECK(array_len);
1426  auto array_idx = cgen_state_->ir_builder_.CreateLoad(
1427  array_idx_ptr->getType()->getPointerElementType(), array_idx_ptr);
1428  auto bound_check = cgen_state_->ir_builder_.CreateICmp(
1429  llvm::ICmpInst::ICMP_SLT, array_idx, array_len);
1430  auto array_loop_body = llvm::BasicBlock::Create(
1431  cgen_state_->context_, "array_loop_body", cgen_state_->current_func_);
1432  cgen_state_->ir_builder_.CreateCondBr(
1433  bound_check,
1434  array_loop_body,
1435  array_loops.empty() ? diamond_codegen.orig_cond_false_ : array_loops.top());
1436  cgen_state_->ir_builder_.SetInsertPoint(array_loop_body);
1437  cgen_state_->ir_builder_.CreateStore(
1438  cgen_state_->ir_builder_.CreateAdd(array_idx, cgen_state_->llInt(int32_t(1))),
1439  array_idx_ptr);
1440  auto array_at_fname = "array_at_" + numeric_type_name(elem_ti);
1441  if (array_ti.get_size() < 0) {
1442  if (array_ti.get_notnull()) {
1443  array_at_fname = "notnull_" + array_at_fname;
1444  }
1445  array_at_fname = "varlen_" + array_at_fname;
1446  }
1447  const auto ar_ret_ty =
1448  elem_ti.is_fp()
1449  ? (elem_ti.get_type() == kDOUBLE
1450  ? llvm::Type::getDoubleTy(cgen_state_->context_)
1451  : llvm::Type::getFloatTy(cgen_state_->context_))
1452  : get_int_type(elem_ti.get_logical_size() * 8, cgen_state_->context_);
1453  group_key = cgen_state_->emitExternalCall(
1454  array_at_fname,
1455  ar_ret_ty,
1456  {group_key, code_generator.posArg(arr_expr), array_idx});
1458  elem_ti, isArchMaxwell(co.device_type), thread_mem_shared)) {
1459  key_to_cache = spillDoubleElement(group_key, ar_ret_ty);
1460  } else {
1461  key_to_cache = group_key;
1462  }
1463  CHECK(array_loop_head);
1464  array_loops.push(array_loop_head);
1465  }
1466  cgen_state_->group_by_expr_cache_.push_back(key_to_cache);
1467  llvm::Value* orig_group_key{nullptr};
1468  if (translate_null_val) {
1469  const std::string translator_func_name(
1470  col_width == sizeof(int32_t) ? "translate_null_key_i32_" : "translate_null_key_");
1471  const auto& ti = group_by_col->get_type_info();
1472  const auto key_type = get_int_type(ti.get_logical_size() * 8, cgen_state_->context_);
1473  orig_group_key = group_key;
1474  group_key = cgen_state_->emitCall(
1475  translator_func_name + numeric_type_name(ti),
1476  {group_key,
1477  static_cast<llvm::Value*>(
1478  llvm::ConstantInt::get(key_type, inline_int_null_val(ti))),
1479  static_cast<llvm::Value*>(llvm::ConstantInt::get(
1480  llvm::Type::getInt64Ty(cgen_state_->context_), translated_null_val))});
1481  }
1482  group_key = cgen_state_->ir_builder_.CreateBitCast(
1483  cgen_state_->castToTypeIn(group_key, col_width * 8),
1484  get_int_type(col_width * 8, cgen_state_->context_));
1485  if (orig_group_key) {
1486  orig_group_key = cgen_state_->ir_builder_.CreateBitCast(
1487  cgen_state_->castToTypeIn(orig_group_key, col_width * 8),
1488  get_int_type(col_width * 8, cgen_state_->context_));
1489  }
1490  return {group_key, orig_group_key};
1491 }
1492 
1494  Executor* executor,
1495  llvm::Value* nullable_lv,
1496  const SQLTypeInfo& nullable_ti,
1497  const std::string& name)
1498  : cgen_state(cgen_state), name(name) {
1499  AUTOMATIC_IR_METADATA(cgen_state);
1500  CHECK(nullable_ti.is_number() || nullable_ti.is_time() || nullable_ti.is_boolean() ||
1501  nullable_ti.is_dict_encoded_string());
1502 
1503  llvm::Value* is_null_lv{nullptr};
1504  if (nullable_ti.is_fp()) {
1505  is_null_lv = cgen_state->ir_builder_.CreateFCmp(
1506  llvm::FCmpInst::FCMP_OEQ, nullable_lv, cgen_state->inlineFpNull(nullable_ti));
1507  } else if (nullable_ti.is_boolean() &&
1508  nullable_lv->getType()->getIntegerBitWidth() == 1) {
1509  is_null_lv = cgen_state->ir_builder_.CreateICmp(
1510  llvm::ICmpInst::ICMP_EQ, nullable_lv, cgen_state->llBool(true));
1511  } else {
1512  is_null_lv = cgen_state->ir_builder_.CreateICmp(
1513  llvm::ICmpInst::ICMP_EQ, nullable_lv, cgen_state->inlineIntNull(nullable_ti));
1514  }
1515  CHECK(is_null_lv);
1516  null_check =
1517  std::make_unique<DiamondCodegen>(is_null_lv, executor, false, name, nullptr, false);
1518 
1519  // generate a phi node depending on whether we got a null or not
1520  nullcheck_bb = llvm::BasicBlock::Create(
1521  cgen_state->context_, name + "_bb", cgen_state->current_func_);
1522 
1523  // update the blocks created by diamond codegen to point to the newly created phi
1524  // block
1525  cgen_state->ir_builder_.SetInsertPoint(null_check->cond_true_);
1526  cgen_state->ir_builder_.CreateBr(nullcheck_bb);
1527  cgen_state->ir_builder_.SetInsertPoint(null_check->cond_false_);
1528 }
1529 
1530 llvm::Value* CodeGenerator::NullCheckCodegen::finalize(llvm::Value* null_lv,
1531  llvm::Value* notnull_lv) {
1532  AUTOMATIC_IR_METADATA(cgen_state);
1533  CHECK(null_check);
1534  cgen_state->ir_builder_.CreateBr(nullcheck_bb);
1535 
1536  CHECK_EQ(null_lv->getType(), notnull_lv->getType());
1537 
1538  cgen_state->ir_builder_.SetInsertPoint(nullcheck_bb);
1539  nullcheck_value =
1540  cgen_state->ir_builder_.CreatePHI(null_lv->getType(), 2, name + "_value");
1541  nullcheck_value->addIncoming(notnull_lv, null_check->cond_false_);
1542  nullcheck_value->addIncoming(null_lv, null_check->cond_true_);
1543 
1544  null_check.reset(nullptr);
1545  cgen_state->ir_builder_.SetInsertPoint(nullcheck_bb);
1546  return nullcheck_value;
1547 }
#define CHECK_EQ(x, y)
Definition: Logger.h:301
bool g_enable_left_join_filter_hoisting
Definition: Execute.cpp:107
NullCheckCodegen(CgenState *cgen_state, Executor *executor, llvm::Value *nullable_lv, const SQLTypeInfo &nullable_ti, const std::string &name="")
Definition: IRCodegen.cpp:1493
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, QueryMemoryDescriptor &query_mem_desc, const CompilationOptions &co, const ExecutionOptions &eo)
Definition: IRCodegen.cpp:1204
#define IS_LOGIC(X)
Definition: sqldefs.h:64
const Expr * get_partition_count() const
Definition: Analyzer.h:1201
#define NULL_DOUBLE
JoinType
Definition: sqldefs.h:238
std::vector< llvm::Value * > outer_join_match_found_per_level_
Definition: CgenState.h:395
bool is_constant_expr() const
Definition: Analyzer.h:1246
std::unordered_map< size_t, std::vector< std::shared_ptr< Analyzer::Expr > > > left_join_non_hashtable_quals_
Definition: PlanState.h:61
llvm::Value * codegenConstantWidthBucketExpr(const Analyzer::WidthBucketExpr *, const CompilationOptions &)
Definition: IRCodegen.cpp:364
llvm::BasicBlock * nullcheck_bb
llvm::Value * element_count
Definition: JoinLoop.h:46
llvm::Value * values_buffer
Definition: JoinLoop.h:49
#define IS_EQUIVALENCE(X)
Definition: sqldefs.h:72
llvm::Value * codegenArith(const Analyzer::BinOper *, const CompilationOptions &)
CgenState * cgen_state_
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:1384
bool is_fp() const
Definition: sqltypes.h:573
llvm::IRBuilder ir_builder_
Definition: CgenState.h:384
std::function< llvm::BasicBlock *(llvm::BasicBlock *, llvm::BasicBlock *, const std::string &, llvm::Function *, CgenState *)> HoistedFiltersCallback
Definition: JoinLoop.h:62
llvm::Value * posArg(const Analyzer::Expr *) const
Definition: ColumnIR.cpp:590
std::string join(T const &container, std::string const &delim)
std::vector< InputDescriptor > input_descs
#define UNREACHABLE()
Definition: Logger.h:338
#define CHECK_GE(x, y)
Definition: Logger.h:306
bool need_patch_unnest_double(const SQLTypeInfo &ti, const bool is_maxwell, const bool mem_shared)
Definition: sqldefs.h:51
llvm::ConstantInt * llBool(const bool v) const
Definition: CgenState.h:263
virtual std::vector< llvm::Value * > codegenColumn(const Analyzer::ColumnVar *, const bool fetch_column, const CompilationOptions &)
Definition: ColumnIR.cpp:94
void set_constant_expr() const
Definition: Analyzer.h:1245
unsigned g_trivial_loop_join_threshold
Definition: Execute.cpp:96
llvm::Value * codegenArrayAt(const Analyzer::BinOper *, const CompilationOptions &)
Definition: ArrayIR.cpp:26
HOST DEVICE SQLTypes get_type() const
Definition: sqltypes.h:391
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:576
double inline_fp_null_val(const SQL_TYPE_INFO &ti)
std::vector< llvm::Value * > codegenGeoBinOper(const Analyzer::GeoBinOper *, const CompilationOptions &)
Definition: GeoIR.cpp:263
bool is_time() const
Definition: sqltypes.h:579
std::shared_ptr< HashJoin > hash_table
Definition: Execute.h:1236
double get_bound_val(const Analyzer::Expr *bound_expr) const
Definition: Analyzer.cpp:3936
std::string to_string(char const *&&v)
llvm::Function * row_func_
Definition: CgenState.h:374
llvm::Value * codegenIsNull(const Analyzer::UOper *, const CompilationOptions &)
Definition: LogicalIR.cpp:381
SQLOps get_optype() const
Definition: Analyzer.h:452
std::vector< llvm::Value * > codegenGeoExpr(const Analyzer::GeoExpr *, const CompilationOptions &)
Definition: GeoIR.cpp:97
llvm::LLVMContext & context_
Definition: CgenState.h:382
llvm::Function * current_func_
Definition: CgenState.h:376
llvm::Value * get_arg_by_name(llvm::Function *func, const std::string &name)
Definition: Execute.h:168
std::set< shared::TableKey > visitFunctionOper(const Analyzer::FunctionOper *func_expr) const final
Definition: IRCodegen.cpp:827
#define INJECT_TIMER(DESC)
Definition: measure.h:122
#define CHECK_NE(x, y)
Definition: Logger.h:302
const JoinQualsPerNestingLevel join_quals
std::vector< llvm::Value * > codegenGeoUOper(const Analyzer::GeoUOper *, const CompilationOptions &)
Definition: GeoIR.cpp:183
llvm::ConstantInt * inlineIntNull(const SQLTypeInfo &)
Definition: CgenState.cpp:65
TableIdToNodeMap table_id_to_node_map
llvm::Value * codegenWidthBucketExpr(const Analyzer::WidthBucketExpr *, const CompilationOptions &)
Definition: IRCodegen.cpp:437
llvm::Value * codegenCastBetweenIntTypes(llvm::Value *operand_lv, const SQLTypeInfo &operand_ti, const SQLTypeInfo &ti, bool upscale=true)
Definition: CastIR.cpp:427
llvm::Value * codegenFunctionOper(const Analyzer::FunctionOper *, const CompilationOptions &)
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:50
void add_qualifier_to_execution_unit(RelAlgExecutionUnit &ra_exe_unit, const std::shared_ptr< Analyzer::Expr > &qual)
Definition: IRCodegen.cpp:535
const std::vector< InputTableInfo > & query_infos_
Definition: PlanState.h:65
bool needs_error_check_
Definition: CgenState.h:405
bool is_boolean() const
Definition: sqltypes.h:582
ExpressionRange getExpressionRange(const Analyzer::BinOper *expr, const std::vector< InputTableInfo > &query_infos, const Executor *, boost::optional< std::list< std::shared_ptr< Analyzer::Expr >>> simple_quals)
std::vector< llvm::Value * > codegenArrayExpr(const Analyzer::ArrayExpr *, const CompilationOptions &)
Definition: ArrayIR.cpp:97
#define AUTOMATIC_IR_METADATA(CGENSTATE)
llvm::BasicBlock * orig_cond_false_
const SQLTypeInfo & get_type_info() const
Definition: Analyzer.h:79
llvm::Value * codegenUMinus(const Analyzer::UOper *, const CompilationOptions &)
llvm::Value * emitCall(const std::string &fname, const std::vector< llvm::Value * > &args)
Definition: CgenState.cpp:217
llvm::Value * slot_lookup_result
Definition: JoinLoop.h:47
ExecutorDeviceType device_type
Definition: sqldefs.h:36
PlanState * plan_state_
std::vector< llvm::Value * > codegen(const Analyzer::Expr *, const bool fetch_columns, const CompilationOptions &)
Definition: IRCodegen.cpp:30
#define CHECK_LT(x, y)
Definition: Logger.h:303
const std::vector< InputTableInfo > & query_infos_
Definition: sqldefs.h:74
Expression class for string functions The &quot;arg&quot; constructor parameter must be an expression that reso...
Definition: Analyzer.h:1601
std::set< shared::TableKey > aggregateResult(const std::set< shared::TableKey > &aggregate, const std::set< shared::TableKey > &next_result) const final
Definition: IRCodegen.cpp:846
#define CHECK_LE(x, y)
Definition: Logger.h:304
std::shared_ptr< HashJoin > buildCurrentLevelHashTable(const JoinCondition &current_level_join_conditions, size_t level_idx, 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:1027
#define IS_ARITHMETIC(X)
Definition: sqldefs.h:65
bool isHintRegistered(const QueryHint hint) const
Definition: QueryHint.h:398
const Expr * get_arg() const
Definition: Analyzer.h:962
std::set< shared::TableKey > visitBinOper(const Analyzer::BinOper *bin_oper) const final
Definition: IRCodegen.cpp:836
std::unordered_map< shared::TableKey, std::unordered_map< int, std::shared_ptr< const ColumnarResults >>> ColumnCacheMap
std::set< shared::TableKey > visitUOper(const Analyzer::UOper *u_oper) const final
Definition: IRCodegen.cpp:842
llvm::StructType * createStringViewStructType()
int32_t get_partition_count_val() const
Definition: Analyzer.cpp:3946
llvm::Value * toBool(llvm::Value *)
Definition: LogicalIR.cpp:344
std::vector< llvm::Value * > codegenGeoColumnVar(const Analyzer::GeoColumnVar *, const bool fetch_columns, const CompilationOptions &co)
Definition: GeoIR.cpp:54
llvm::Value * codegenFunctionOperWithCustomTypeHandling(const Analyzer::FunctionOperWithCustomTypeHandling *, const CompilationOptions &)
llvm::Value * codegenCmp(const Analyzer::BinOper *, const CompilationOptions &)
Definition: CompareIR.cpp:230
std::list< std::shared_ptr< Analyzer::Expr > > getSimpleQuals() const
Definition: PlanState.h:97
const Expr * get_target_value() const
Definition: Analyzer.h:1198
std::list< std::shared_ptr< Analyzer::Expr > > quals
llvm::ConstantInt * llInt(const T v) const
Definition: CgenState.h:249
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:1186
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:1530
#define CHECK(condition)
Definition: Logger.h:291
bool can_skip_out_of_bound_check() const
Definition: Analyzer.h:1243
llvm::Value * codegenLogical(const Analyzer::BinOper *, const CompilationOptions &)
Definition: LogicalIR.cpp:299
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:545
int64_t inline_int_null_val(const SQL_TYPE_INFO &ti)
llvm::ConstantInt * ll_bool(const bool v, llvm::LLVMContext &context)
size_t loop_join_inner_table_max_num_rows
Definition: QueryHint.h:372
llvm::Value * codegenCast(const Analyzer::UOper *, const CompilationOptions &)
Definition: CastIR.cpp:21
uint32_t log2_bytes(const uint32_t bytes)
Definition: Execute.h:198
std::string numeric_type_name(const SQLTypeInfo &ti)
Definition: Execute.h:230
bool is_dict_encoded_string() const
Definition: sqltypes.h:643
Definition: sqltypes.h:72
void skip_out_of_bound_check() const
Definition: Analyzer.h:1244
void redeclareFilterFunction()
Definition: IRCodegen.cpp:1087
bool any_of(std::vector< Analyzer::Expr * > const &target_exprs)
const Expr * get_lower_bound() const
Definition: Analyzer.h:1199
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:610
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:968
string name
Definition: setup.in.py:72
JoinLoop::HoistedFiltersCallback buildHoistLeftHandSideFiltersCb(const RelAlgExecutionUnit &ra_exe_unit, const size_t level_idx, const shared::TableKey &inner_table_key, const CompilationOptions &co)
Definition: IRCodegen.cpp:859
const Expr * get_upper_bound() const
Definition: Analyzer.h:1200
const size_t g_maximum_conditions_to_coalesce
Definition: Datum.h:71
llvm::ArrayType * get_int_array_type(int const width, int count, llvm::LLVMContext &context)
Definition: sqldefs.h:41
SQLOps get_optype() const
Definition: Analyzer.h:383
#define VLOG(n)
Definition: Logger.h:388
std::unique_ptr< DiamondCodegen > null_check
std::set< shared::TableKey > visitColumnVar(const Analyzer::ColumnVar *col_expr) const final
Definition: IRCodegen.cpp:822
std::list< std::shared_ptr< Analyzer::Expr > > simple_quals
#define IS_COMPARISON(X)
Definition: sqldefs.h:61
double doubleval
Definition: Datum.h:78
HashTableBuildDagMap hash_table_build_plan_dag
llvm::ConstantFP * inlineFpNull(const SQLTypeInfo &)
Definition: CgenState.cpp:104
void check_valid_join_qual(std::shared_ptr< Analyzer::BinOper > &bin_oper)
Definition: IRCodegen.cpp:586
Executor * executor() const
size_t get_loop_join_size(const std::vector< InputTableInfo > &query_infos, const RelAlgExecutionUnit &ra_exe_unit)
Definition: Execute.cpp:1905
RUNTIME_EXPORT ALWAYS_INLINE DEVICE int32_t width_bucket_expr(const double target_value, const bool reversed, const double lower_bound, const double upper_bound, const int32_t partition_count)