OmniSciDB  a5dc49c757
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
CompareIR.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 "CodeGenerator.h"
18 #include "Execute.h"
19 
20 #include <typeinfo>
21 
22 #include "../Parser/ParserNode.h"
23 
24 namespace {
25 
26 llvm::CmpInst::Predicate llvm_icmp_pred(const SQLOps op_type) {
27  switch (op_type) {
28  case kEQ:
29  return llvm::ICmpInst::ICMP_EQ;
30  case kNE:
31  return llvm::ICmpInst::ICMP_NE;
32  case kLT:
33  return llvm::ICmpInst::ICMP_SLT;
34  case kGT:
35  return llvm::ICmpInst::ICMP_SGT;
36  case kLE:
37  return llvm::ICmpInst::ICMP_SLE;
38  case kGE:
39  return llvm::ICmpInst::ICMP_SGE;
40  default:
41  abort();
42  }
43 }
44 
45 std::string icmp_name(const SQLOps op_type) {
46  switch (op_type) {
47  case kEQ:
48  return "eq";
49  case kNE:
50  return "ne";
51  case kLT:
52  return "lt";
53  case kGT:
54  return "gt";
55  case kLE:
56  return "le";
57  case kGE:
58  return "ge";
59  default:
60  abort();
61  }
62 }
63 
64 std::string icmp_arr_name(const SQLOps op_type) {
65  switch (op_type) {
66  case kEQ:
67  return "eq";
68  case kNE:
69  return "ne";
70  case kLT:
71  return "gt";
72  case kGT:
73  return "lt";
74  case kLE:
75  return "ge";
76  case kGE:
77  return "le";
78  default:
79  abort();
80  }
81 }
82 
83 llvm::CmpInst::Predicate llvm_fcmp_pred(const SQLOps op_type) {
84  switch (op_type) {
85  case kEQ:
86  return llvm::CmpInst::FCMP_OEQ;
87  case kNE:
88  return llvm::CmpInst::FCMP_ONE;
89  case kLT:
90  return llvm::CmpInst::FCMP_OLT;
91  case kGT:
92  return llvm::CmpInst::FCMP_OGT;
93  case kLE:
94  return llvm::CmpInst::FCMP_OLE;
95  case kGE:
96  return llvm::CmpInst::FCMP_OGE;
97  default:
98  abort();
99  }
100 }
101 
102 } // namespace
103 
104 namespace {
105 
106 std::string string_cmp_func(const SQLOps optype) {
107  switch (optype) {
108  case kLT:
109  return "string_lt";
110  case kLE:
111  return "string_le";
112  case kGT:
113  return "string_gt";
114  case kGE:
115  return "string_ge";
116  case kEQ:
117  return "string_eq";
118  case kNE:
119  return "string_ne";
120  default:
121  abort();
122  }
123 }
124 
125 std::shared_ptr<Analyzer::BinOper> lower_bw_eq(const Analyzer::BinOper* bw_eq) {
126  const auto eq_oper =
127  std::make_shared<Analyzer::BinOper>(bw_eq->get_type_info(),
128  bw_eq->get_contains_agg(),
129  kEQ,
130  bw_eq->get_qualifier(),
131  bw_eq->get_own_left_operand(),
132  bw_eq->get_own_right_operand());
133  const auto lhs_is_null =
134  std::make_shared<Analyzer::UOper>(kBOOLEAN, kISNULL, bw_eq->get_own_left_operand());
135  const auto rhs_is_null = std::make_shared<Analyzer::UOper>(
137  const auto both_are_null =
138  Parser::OperExpr::normalize(kAND, kONE, lhs_is_null, rhs_is_null);
139  const auto bw_eq_oper = std::dynamic_pointer_cast<Analyzer::BinOper>(
140  Parser::OperExpr::normalize(kOR, kONE, eq_oper, both_are_null));
141  CHECK(bw_eq_oper);
142  return bw_eq_oper;
143 }
144 
145 std::shared_ptr<Analyzer::BinOper> make_eq(const std::shared_ptr<Analyzer::Expr>& lhs,
146  const std::shared_ptr<Analyzer::Expr>& rhs,
147  const SQLOps optype) {
148  CHECK(IS_EQUIVALENCE(optype));
149  // Sides of a tuple equality are stripped of cast operators to simplify the logic
150  // in the hash table construction algorithm. Add them back here.
151  auto eq_oper = std::dynamic_pointer_cast<Analyzer::BinOper>(
152  Parser::OperExpr::normalize(optype, kONE, lhs, rhs));
153  CHECK(eq_oper);
154  return optype == kBW_EQ ? lower_bw_eq(eq_oper.get()) : eq_oper;
155 }
156 
157 // Convert a column tuple equality expression back to a conjunction of comparisons
158 // so that it can be handled by the regular code generation methods.
159 std::shared_ptr<Analyzer::BinOper> lower_multicol_compare(
160  const Analyzer::BinOper* multicol_compare) {
161  const auto left_tuple_expr = dynamic_cast<const Analyzer::ExpressionTuple*>(
162  multicol_compare->get_left_operand());
163  const auto right_tuple_expr = dynamic_cast<const Analyzer::ExpressionTuple*>(
164  multicol_compare->get_right_operand());
165  CHECK(left_tuple_expr && right_tuple_expr);
166  const auto& left_tuple = left_tuple_expr->getTuple();
167  const auto& right_tuple = right_tuple_expr->getTuple();
168  CHECK_EQ(left_tuple.size(), right_tuple.size());
169  CHECK_GT(left_tuple.size(), size_t(1));
170  auto acc =
171  make_eq(left_tuple.front(), right_tuple.front(), multicol_compare->get_optype());
172  for (size_t i = 1; i < left_tuple.size(); ++i) {
173  auto crt = make_eq(left_tuple[i], right_tuple[i], multicol_compare->get_optype());
174  const bool not_null =
175  acc->get_type_info().get_notnull() && crt->get_type_info().get_notnull();
176  acc = makeExpr<Analyzer::BinOper>(
177  SQLTypeInfo(kBOOLEAN, not_null), false, kAND, kONE, acc, crt);
178  }
179  return acc;
180 }
181 
183  auto lhs_cv = dynamic_cast<const Analyzer::ColumnVar*>(bin_oper->get_left_operand());
184  auto rhs_cv = dynamic_cast<const Analyzer::ColumnVar*>(bin_oper->get_right_operand());
185  auto comp_op = IS_COMPARISON(bin_oper->get_optype());
186  if (lhs_cv && rhs_cv && comp_op) {
187  auto lhs_ti = lhs_cv->get_type_info();
188  auto rhs_ti = rhs_cv->get_type_info();
189  if (lhs_ti.is_array() && rhs_ti.is_array()) {
190  throw std::runtime_error(
191  "Comparing two full array columns is not supported yet. Please consider "
192  "rewriting the full array comparison to a comparison between indexed array "
193  "columns "
194  "(i.e., arr1[1] {<, <=, >, >=} arr2[1]).");
195  }
196  }
197  auto lhs_bin_oper =
198  dynamic_cast<const Analyzer::BinOper*>(bin_oper->get_left_operand());
199  auto rhs_bin_oper =
200  dynamic_cast<const Analyzer::BinOper*>(bin_oper->get_right_operand());
201  // we can do (non-)equivalence check of two encoded string
202  // even if they are (indexed) array cols
203  auto theta_comp = IS_COMPARISON(bin_oper->get_optype()) &&
204  !IS_EQUIVALENCE(bin_oper->get_optype()) &&
205  bin_oper->get_optype() != SQLOps::kNE;
206  if (lhs_bin_oper && rhs_bin_oper && theta_comp &&
207  lhs_bin_oper->get_optype() == SQLOps::kARRAY_AT &&
208  rhs_bin_oper->get_optype() == SQLOps::kARRAY_AT) {
209  auto lhs_arr_cv =
210  dynamic_cast<const Analyzer::ColumnVar*>(lhs_bin_oper->get_left_operand());
211  auto lhs_arr_idx =
212  dynamic_cast<const Analyzer::Constant*>(lhs_bin_oper->get_right_operand());
213  auto rhs_arr_cv =
214  dynamic_cast<const Analyzer::ColumnVar*>(rhs_bin_oper->get_left_operand());
215  auto rhs_arr_idx =
216  dynamic_cast<const Analyzer::Constant*>(rhs_bin_oper->get_right_operand());
217  if (lhs_arr_cv && rhs_arr_cv && lhs_arr_idx && rhs_arr_idx &&
218  ((lhs_arr_cv->get_type_info().is_array() &&
219  lhs_arr_cv->get_type_info().get_subtype() == SQLTypes::kTEXT) ||
220  (rhs_arr_cv->get_type_info().is_string() &&
221  rhs_arr_cv->get_type_info().get_subtype() == SQLTypes::kTEXT))) {
222  throw std::runtime_error(
223  "Comparison between string array columns is not supported yet.");
224  }
225  }
226 }
227 
228 } // namespace
229 
230 llvm::Value* CodeGenerator::codegenCmp(const Analyzer::BinOper* bin_oper,
231  const CompilationOptions& co) {
233  const auto qualifier = bin_oper->get_qualifier();
234  const auto lhs = bin_oper->get_left_operand();
235  const auto rhs = bin_oper->get_right_operand();
236  if (dynamic_cast<const Analyzer::ExpressionTuple*>(lhs)) {
237  CHECK(dynamic_cast<const Analyzer::ExpressionTuple*>(rhs));
238  const auto lowered = lower_multicol_compare(bin_oper);
239  const auto lowered_lvs = codegen(lowered.get(), true, co);
240  CHECK_EQ(size_t(1), lowered_lvs.size());
241  return lowered_lvs.front();
242  }
243  const auto optype = bin_oper->get_optype();
244  if (optype == kBW_EQ) {
245  const auto bw_eq_oper = lower_bw_eq(bin_oper);
246  return codegenLogical(bw_eq_oper.get(), co);
247  }
248  if (optype == kBBOX_INTERSECT) {
249  return codegenBoundingBoxIntersect(optype,
250  qualifier,
251  bin_oper->get_own_left_operand(),
252  bin_oper->get_own_right_operand(),
253  co);
254  }
255  if (is_unnest(lhs) || is_unnest(rhs)) {
256  throw std::runtime_error("Unnest not supported in comparisons");
257  }
258  check_array_comp_cond(bin_oper);
259  const auto& lhs_ti = lhs->get_type_info();
260  const auto& rhs_ti = rhs->get_type_info();
261 
262  if (lhs_ti.is_string() && rhs_ti.is_string() &&
263  !(IS_EQUIVALENCE(optype) || optype == kNE)) {
264  auto cmp_str = codegenStrCmp(optype,
265  qualifier,
266  bin_oper->get_own_left_operand(),
267  bin_oper->get_own_right_operand(),
268  co);
269  if (cmp_str) {
270  return cmp_str;
271  }
272  }
273 
274  if (lhs_ti.is_decimal()) {
275  auto cmp_decimal_const =
276  codegenCmpDecimalConst(optype, qualifier, lhs, lhs_ti, rhs, co);
277  if (cmp_decimal_const) {
278  return cmp_decimal_const;
279  }
280  }
281  auto lhs_lvs = codegen(lhs, true, co);
282  return codegenCmp(optype, qualifier, lhs_lvs, lhs_ti, rhs, co);
283 }
284 
286  const SQLOps optype,
287  const SQLQualifier qualifier,
288  const std::shared_ptr<Analyzer::Expr> lhs,
289  const std::shared_ptr<Analyzer::Expr> rhs,
290  const CompilationOptions& co) {
292  const auto lhs_ti = lhs->get_type_info();
294  // failed to build a suitable hash table. short circuit the bounding box interesect
295  // expression by always returning true. this will fall into the ST_Contains check,
296  // which will do bounding box intersection before the heavier contains computation.
297  VLOG(1) << "Failed to build bounding box intersect hash table, short circuiting "
298  "bounding box intersect operator.";
299  return llvm::ConstantInt::get(get_int_type(8, cgen_state_->context_), true);
300  }
301  // TODO(adb): we should never get here, but going to leave this in place for now since
302  // it will likely be useful in factoring the bounds check out of ST_Contains
303  CHECK(lhs_ti.is_geometry());
304 
305  if (lhs_ti.is_geometry()) {
306  // only point in linestring/poly/mpoly is currently supported
307  CHECK(lhs_ti.get_type() == kPOINT);
308  const auto lhs_col = dynamic_cast<Analyzer::ColumnVar*>(lhs.get());
309  CHECK(lhs_col);
310 
311  // Get the actual point data column descriptor
312  auto lhs_column_key = lhs_col->getColumnKey();
313  lhs_column_key.column_id = lhs_column_key.column_id + 1;
314  const auto coords_cd = Catalog_Namespace::get_metadata_for_column(lhs_column_key);
315  CHECK(coords_cd);
316 
317  std::vector<std::shared_ptr<Analyzer::Expr>> geoargs;
318  geoargs.push_back(makeExpr<Analyzer::ColumnVar>(
319  coords_cd->columnType,
320  shared::ColumnKey{lhs_col->getTableKey(), coords_cd->columnId},
321  lhs_col->get_rte_idx()));
322 
323  Datum input_compression;
324  input_compression.intval =
325  (lhs_ti.get_compression() == kENCODING_GEOINT && lhs_ti.get_comp_param() == 32)
326  ? 1
327  : 0;
328  geoargs.push_back(makeExpr<Analyzer::Constant>(kINT, false, input_compression));
329  Datum input_srid;
330  input_srid.intval = lhs_ti.get_input_srid();
331  geoargs.push_back(makeExpr<Analyzer::Constant>(kINT, false, input_srid));
332  Datum output_srid;
333  output_srid.intval = lhs_ti.get_output_srid();
334  geoargs.push_back(makeExpr<Analyzer::Constant>(kINT, false, output_srid));
335 
336  const auto x_ptr_oper = makeExpr<Analyzer::FunctionOper>(
337  SQLTypeInfo(kDOUBLE, true), "ST_X_Point", geoargs);
338  const auto y_ptr_oper = makeExpr<Analyzer::FunctionOper>(
339  SQLTypeInfo(kDOUBLE, true), "ST_Y_Point", geoargs);
340 
341  const auto rhs_ti = rhs->get_type_info();
342  CHECK(IS_GEO_POLY(rhs_ti.get_type()));
343  const auto rhs_col = dynamic_cast<Analyzer::ColumnVar*>(rhs.get());
344  CHECK(rhs_col);
345 
346  auto rhs_column_key = rhs_col->getColumnKey();
347  rhs_column_key.column_id =
348  rhs_column_key.column_id + rhs_ti.get_physical_coord_cols() + 1;
349  const auto poly_bounds_cd =
351  CHECK(poly_bounds_cd);
352 
353  auto bbox_col_var = makeExpr<Analyzer::ColumnVar>(
354  poly_bounds_cd->columnType,
355  shared::ColumnKey{rhs_col->getTableKey(), poly_bounds_cd->columnId},
356  rhs_col->get_rte_idx());
357 
358  const auto bbox_contains_func_oper =
359  makeExpr<Analyzer::FunctionOper>(SQLTypeInfo(kBOOLEAN, false),
360  "Point_Overlaps_Box",
361  std::vector<std::shared_ptr<Analyzer::Expr>>{
362  bbox_col_var, x_ptr_oper, y_ptr_oper});
363 
364  return codegenFunctionOper(bbox_contains_func_oper.get(), co);
365  }
366 
367  CHECK(false) << "Unsupported type for bounding box intersect operator: "
368  << lhs_ti.get_type_name();
369  return nullptr;
370 }
371 
372 llvm::Value* CodeGenerator::codegenStrCmp(const SQLOps optype,
373  const SQLQualifier qualifier,
374  const std::shared_ptr<Analyzer::Expr> lhs,
375  const std::shared_ptr<Analyzer::Expr> rhs,
376  const CompilationOptions& co) {
378  const auto lhs_ti = lhs->get_type_info();
379  const auto rhs_ti = rhs->get_type_info();
380 
381  CHECK(lhs_ti.is_string());
382  CHECK(rhs_ti.is_string());
383 
384  const auto null_check_suffix = get_null_check_suffix(lhs_ti, rhs_ti);
385  if (lhs_ti.get_compression() == kENCODING_DICT &&
386  rhs_ti.get_compression() == kENCODING_DICT) {
387  if (lhs_ti.getStringDictKey() == rhs_ti.getStringDictKey()) {
388  // Both operands share a dictionary
389  // check if query is trying to compare a column against literal
390  auto ir = codegenDictStrCmp(lhs, rhs, optype, co);
391  if (ir) {
392  return ir;
393  }
394  } else {
395  // Both operands don't share a dictionary
396  return nullptr;
397  }
398  }
399  return nullptr;
400 }
401 
403  const SQLQualifier qualifier,
404  const Analyzer::Expr* lhs,
405  const SQLTypeInfo& lhs_ti,
406  const Analyzer::Expr* rhs,
407  const CompilationOptions& co) {
409  auto u_oper = dynamic_cast<const Analyzer::UOper*>(lhs);
410  if (!u_oper || u_oper->get_optype() != kCAST) {
411  return nullptr;
412  }
413  auto rhs_constant = dynamic_cast<const Analyzer::Constant*>(rhs);
414  if (!rhs_constant) {
415  return nullptr;
416  }
417  const auto operand = u_oper->get_operand();
418  const auto& operand_ti = operand->get_type_info();
419  if (operand_ti.is_decimal() && operand_ti.get_scale() < lhs_ti.get_scale()) {
420  // lhs decimal type has smaller scale
421  } else if (operand_ti.is_integer() && 0 < lhs_ti.get_scale()) {
422  // lhs is integer, no need to scale it all the way up to the cmp expr scale
423  } else {
424  return nullptr;
425  }
426 
427  auto scale_diff = lhs_ti.get_scale() - operand_ti.get_scale() - 1;
428  int64_t bigintval = rhs_constant->get_constval().bigintval;
429  bool negative = false;
430  if (bigintval < 0) {
431  negative = true;
432  bigintval = -bigintval;
433  }
434  int64_t truncated_decimal = bigintval / exp_to_scale(scale_diff);
435  int64_t decimal_tail = bigintval % exp_to_scale(scale_diff);
436  if (truncated_decimal % 10 == 0 && decimal_tail > 0) {
437  truncated_decimal += 1;
438  }
441  lhs_ti.get_scale() - scale_diff,
442  operand_ti.get_notnull());
443  if (negative) {
444  truncated_decimal = -truncated_decimal;
445  }
446  Datum d;
447  d.bigintval = truncated_decimal;
448  const auto new_rhs_lit =
449  makeExpr<Analyzer::Constant>(new_ti, rhs_constant->get_is_null(), d);
450  const auto operand_lv = codegen(operand, true, co).front();
451  const auto lhs_lv = codegenCast(operand_lv, operand_ti, new_ti, false, co);
452  return codegenCmp(optype, qualifier, {lhs_lv}, new_ti, new_rhs_lit.get(), co);
453 }
454 
455 namespace {
456 void unpack_none_encoded_string(CgenState* cgen_state, std::vector<llvm::Value*>& lvs) {
457  if (lvs.size() != 3) {
458  CHECK_EQ(size_t(1), lvs.size());
459  lvs.push_back(cgen_state->ir_builder_.CreateExtractValue(lvs[0], 0));
460  lvs.push_back(cgen_state->ir_builder_.CreateExtractValue(lvs[0], 1));
461  lvs.back() = cgen_state->ir_builder_.CreateTrunc(
462  lvs.back(), llvm::Type::getInt32Ty(cgen_state->context_));
463  }
464  CHECK_EQ(lvs.size(), size_t(3));
465 }
467  Executor* executor,
468  SQLTypeInfo const ti,
469  llvm::StructType* string_view_struct_type,
470  std::vector<llvm::Value*>& lvs) {
471  const auto sdp_ptr = reinterpret_cast<int64_t>(executor->getStringDictionaryProxy(
472  ti.getStringDictKey(), executor->getRowSetMemoryOwner(), true));
473  const auto sv = cgen_state->emitExternalCall(
474  "string_decompress", string_view_struct_type, {lvs[0], cgen_state->llInt(sdp_ptr)});
475  lvs.push_back(cgen_state->ir_builder_.CreateExtractValue(sv, 0));
476  lvs.push_back(cgen_state->ir_builder_.CreateExtractValue(sv, 1));
477  lvs.back() = cgen_state->ir_builder_.CreateTrunc(
478  lvs.back(), llvm::Type::getInt32Ty(cgen_state->context_));
479 }
480 } // namespace
481 
482 llvm::Value* CodeGenerator::codegenCmp(const SQLOps optype,
483  const SQLQualifier qualifier,
484  std::vector<llvm::Value*> lhs_lvs,
485  const SQLTypeInfo& lhs_ti,
486  const Analyzer::Expr* rhs,
487  const CompilationOptions& co) {
489  CHECK(IS_COMPARISON(optype));
490  const auto& rhs_ti = rhs->get_type_info();
491  if (rhs_ti.is_array()) {
492  return codegenQualifierCmp(optype, qualifier, lhs_lvs, rhs, co);
493  }
494  auto rhs_lvs = codegen(rhs, true, co);
495  CHECK_EQ(kONE, qualifier);
496  if (optype == kBBOX_INTERSECT) {
497  CHECK(lhs_ti.is_geometry());
498  CHECK(rhs_ti.is_array() ||
499  rhs_ti.is_geometry()); // allow geo col or bounds col to pass
500  } else {
501  CHECK((lhs_ti.get_type() == rhs_ti.get_type()) ||
502  (lhs_ti.is_string() && rhs_ti.is_string()));
503  }
504  const auto null_check_suffix = get_null_check_suffix(lhs_ti, rhs_ti);
505  if (lhs_ti.is_integer() || lhs_ti.is_decimal() || lhs_ti.is_time() ||
506  lhs_ti.is_boolean() || lhs_ti.is_string() || lhs_ti.is_timeinterval()) {
507  if (lhs_ti.is_string()) {
508  CHECK(rhs_ti.is_string());
509  // we sync two string col's encoding scheme
510  // if one of them is dict-encoded before reaching here,
511  // i.e., call `codegenCastNonStringToString` or `codegenCastFromString`
512  CHECK_EQ(lhs_ti.get_compression(), rhs_ti.get_compression());
513  bool unpack_strings = true;
514  if (lhs_ti.get_compression() == kENCODING_NONE) {
517  } else if (lhs_ti.get_compression() == kENCODING_DICT) {
518  if (IS_EQUIVALENCE(optype) || optype == kNE) {
519  // we use `StringDictionaryTranslationMgr` to translate
520  // dict-encoded lhs against rhs's string dictionary
521  // and then compare their string ids without unpacking strings
522  // i.e., call `eq_int32_t_nullable` instead of `string_eq_nullable`
523  unpack_strings = false;
524  } else {
525  auto sv_struct_type_lv = createStringViewStructType();
527  cgen_state_, executor_, lhs_ti, sv_struct_type_lv, lhs_lvs);
529  cgen_state_, executor_, rhs_ti, sv_struct_type_lv, rhs_lvs);
530  }
531  }
532  if (unpack_strings) {
533  // we directly compare two unpacked (i.e., raw) strings
534  std::vector<llvm::Value*> str_cmp_args{
535  lhs_lvs[1], lhs_lvs[2], rhs_lvs[1], rhs_lvs[2]};
536  if (!null_check_suffix.empty()) {
537  str_cmp_args.push_back(
539  }
540  return cgen_state_->emitCall(
541  string_cmp_func(optype) + (null_check_suffix.empty() ? "" : "_nullable"),
542  str_cmp_args);
543  }
544  }
545 
546  if (lhs_ti.is_boolean() && rhs_ti.is_boolean()) {
547  auto& lhs_lv = lhs_lvs.front();
548  auto& rhs_lv = rhs_lvs.front();
549  CHECK(lhs_lv->getType()->isIntegerTy());
550  CHECK(rhs_lv->getType()->isIntegerTy());
551  if (lhs_lv->getType()->getIntegerBitWidth() <
552  rhs_lv->getType()->getIntegerBitWidth()) {
553  lhs_lv =
554  cgen_state_->castToTypeIn(lhs_lv, rhs_lv->getType()->getIntegerBitWidth());
555  } else {
556  rhs_lv =
557  cgen_state_->castToTypeIn(rhs_lv, lhs_lv->getType()->getIntegerBitWidth());
558  }
559  }
560 
561  return null_check_suffix.empty()
562  ? cgen_state_->ir_builder_.CreateICmp(
563  llvm_icmp_pred(optype), lhs_lvs.front(), rhs_lvs.front())
565  icmp_name(optype) + "_" + numeric_type_name(lhs_ti) +
566  null_check_suffix,
567  {lhs_lvs.front(),
568  rhs_lvs.front(),
571  }
572  if (lhs_ti.get_type() == kFLOAT || lhs_ti.get_type() == kDOUBLE) {
573  return null_check_suffix.empty()
574  ? cgen_state_->ir_builder_.CreateFCmp(
575  llvm_fcmp_pred(optype), lhs_lvs.front(), rhs_lvs.front())
577  icmp_name(optype) + "_" + numeric_type_name(lhs_ti) +
578  null_check_suffix,
579  {lhs_lvs.front(),
580  rhs_lvs.front(),
581  lhs_ti.get_type() == kFLOAT ? cgen_state_->llFp(NULL_FLOAT)
584  }
585  CHECK(false);
586  return nullptr;
587 }
588 
589 llvm::Value* CodeGenerator::codegenQualifierCmp(const SQLOps optype,
590  const SQLQualifier qualifier,
591  std::vector<llvm::Value*> lhs_lvs,
592  const Analyzer::Expr* rhs,
593  const CompilationOptions& co) {
595  const auto& rhs_ti = rhs->get_type_info();
596  const Analyzer::Expr* arr_expr{rhs};
597  if (dynamic_cast<const Analyzer::UOper*>(rhs)) {
598  const auto cast_arr = static_cast<const Analyzer::UOper*>(rhs);
599  CHECK_EQ(kCAST, cast_arr->get_optype());
600  arr_expr = cast_arr->get_operand();
601  }
602  const auto& arr_ti = arr_expr->get_type_info();
603  const auto& elem_ti = arr_ti.get_elem_type();
604  auto rhs_lvs = codegen(arr_expr, true, co);
605  CHECK_NE(kONE, qualifier);
606  std::string fname{std::string("array_") + (qualifier == kANY ? "any" : "all") + "_" +
607  icmp_arr_name(optype)};
608  const auto& target_ti = rhs_ti.get_elem_type();
609  const bool is_real_string{target_ti.is_string() &&
610  target_ti.get_compression() != kENCODING_DICT};
611  if (is_real_string) {
612  if (g_cluster) {
613  throw std::runtime_error(
614  "Comparison between a dictionary-encoded and a none-encoded string not "
615  "supported for distributed queries");
616  }
617  if (g_enable_watchdog) {
618  throw WatchdogException(
619  "Comparison between a dictionary-encoded and a none-encoded string would be "
620  "slow");
621  }
623  throw QueryMustRunOnCpu();
624  }
625  CHECK_EQ(kENCODING_NONE, target_ti.get_compression());
626  fname += "_str";
627  }
628  if (elem_ti.is_integer() || elem_ti.is_boolean() || elem_ti.is_string() ||
629  elem_ti.is_decimal()) {
630  fname += ("_" + numeric_type_name(elem_ti));
631  } else {
632  CHECK(elem_ti.is_fp());
633  fname += elem_ti.get_type() == kDOUBLE ? "_double" : "_float";
634  }
635  if (is_real_string) {
636  CHECK_EQ(size_t(3), lhs_lvs.size());
638  fname,
640  {rhs_lvs.front(),
641  posArg(arr_expr),
642  lhs_lvs[1],
643  lhs_lvs[2],
644  cgen_state_->llInt(int64_t(executor()->getStringDictionaryProxy(
645  elem_ti.getStringDictKey(), executor()->getRowSetMemoryOwner(), true))),
646  cgen_state_->inlineIntNull(elem_ti)});
647  }
648  if (target_ti.is_integer() || target_ti.is_boolean() || target_ti.is_string() ||
649  target_ti.is_decimal()) {
650  fname += ("_" + numeric_type_name(target_ti));
651  } else {
652  CHECK(target_ti.is_fp());
653  fname += target_ti.get_type() == kDOUBLE ? "_double" : "_float";
654  }
655  return cgen_state_->emitExternalCall(
656  fname,
657  get_int_type(1, cgen_state_->context_),
658  {rhs_lvs.front(),
659  posArg(arr_expr),
660  lhs_lvs.front(),
661  elem_ti.is_fp() ? static_cast<llvm::Value*>(cgen_state_->inlineFpNull(elem_ti))
662  : static_cast<llvm::Value*>(cgen_state_->inlineIntNull(elem_ti))});
663 }
void check_array_comp_cond(const Analyzer::BinOper *bin_oper)
Definition: CompareIR.cpp:182
static constexpr int32_t kMaxRepresentableNumericPrecision
Definition: sqltypes.h:60
#define CHECK_EQ(x, y)
Definition: Logger.h:301
llvm::Value * castToTypeIn(llvm::Value *val, const size_t bit_width)
Definition: CgenState.cpp:150
#define NULL_DOUBLE
llvm::Value * codegenStrCmp(const SQLOps, const SQLQualifier, const std::shared_ptr< Analyzer::Expr >, const std::shared_ptr< Analyzer::Expr >, const CompilationOptions &)
Definition: CompareIR.cpp:372
std::string icmp_name(const SQLOps op_type)
Definition: CompareIR.cpp:45
#define IS_EQUIVALENCE(X)
Definition: sqldefs.h:72
CgenState * cgen_state_
#define NULL_FLOAT
SQLQualifier
Definition: sqldefs.h:74
std::shared_ptr< Analyzer::BinOper > lower_multicol_compare(const Analyzer::BinOper *multicol_compare)
Definition: CompareIR.cpp:159
HOST DEVICE int get_scale() const
Definition: sqltypes.h:396
const Expr * get_right_operand() const
Definition: Analyzer.h:456
SQLOps
Definition: sqldefs.h:31
Definition: sqldefs.h:37
llvm::IRBuilder ir_builder_
Definition: CgenState.h:384
static std::shared_ptr< Analyzer::Expr > normalize(const SQLOps optype, const SQLQualifier qual, std::shared_ptr< Analyzer::Expr > left_expr, std::shared_ptr< Analyzer::Expr > right_expr, const Executor *executor=nullptr)
Definition: ParserNode.cpp:380
Definition: sqldefs.h:38
llvm::Value * posArg(const Analyzer::Expr *) const
Definition: ColumnIR.cpp:590
Definition: sqldefs.h:40
const ColumnDescriptor * get_metadata_for_column(const ::shared::ColumnKey &column_key)
bool get_contains_agg() const
Definition: Analyzer.h:81
void unpack_dict_encoded_string(CgenState *cgen_state, Executor *executor, SQLTypeInfo const ti, llvm::StructType *string_view_struct_type, std::vector< llvm::Value * > &lvs)
Definition: CompareIR.cpp:466
Definition: sqldefs.h:51
Definition: sqldefs.h:32
std::shared_ptr< Analyzer::BinOper > lower_bw_eq(const Analyzer::BinOper *bw_eq)
Definition: CompareIR.cpp:125
HOST DEVICE SQLTypes get_type() const
Definition: sqltypes.h:391
llvm::CmpInst::Predicate llvm_fcmp_pred(const SQLOps op_type)
Definition: CompareIR.cpp:83
llvm::Type * get_int_type(const int width, llvm::LLVMContext &context)
#define CHECK_GT(x, y)
Definition: Logger.h:305
int32_t intval
Definition: Datum.h:75
bool is_time() const
Definition: sqltypes.h:579
std::string icmp_arr_name(const SQLOps op_type)
Definition: CompareIR.cpp:64
SQLOps get_optype() const
Definition: Analyzer.h:452
llvm::LLVMContext & context_
Definition: CgenState.h:382
llvm::Value * codegenCmpDecimalConst(const SQLOps, const SQLQualifier, const Analyzer::Expr *, const SQLTypeInfo &, const Analyzer::Expr *, const CompilationOptions &)
Definition: CompareIR.cpp:402
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.cpp:395
bool is_integer() const
Definition: sqltypes.h:567
#define CHECK_NE(x, y)
Definition: Logger.h:302
llvm::ConstantInt * inlineIntNull(const SQLTypeInfo &)
Definition: CgenState.cpp:65
int64_t bigintval
Definition: Datum.h:76
bool is_timeinterval() const
Definition: sqltypes.h:594
llvm::Value * codegenFunctionOper(const Analyzer::FunctionOper *, const CompilationOptions &)
Executor * executor_
Definition: sqldefs.h:39
bool g_enable_watchdog
Definition: sqldefs.h:74
llvm::ConstantFP * llFp(const float v) const
Definition: CgenState.h:253
llvm::Value * codegenDictStrCmp(const std::shared_ptr< Analyzer::Expr >, const std::shared_ptr< Analyzer::Expr >, const SQLOps, const CompilationOptions &co)
bool is_boolean() const
Definition: sqltypes.h:582
#define AUTOMATIC_IR_METADATA(CGENSTATE)
std::string get_null_check_suffix(const SQLTypeInfo &lhs_ti, const SQLTypeInfo &rhs_ti)
Definition: Execute.h:1661
const SQLTypeInfo & get_type_info() const
Definition: Analyzer.h:79
llvm::Value * emitCall(const std::string &fname, const std::vector< llvm::Value * > &args)
Definition: CgenState.cpp:217
ExecutorDeviceType device_type
Definition: sqldefs.h:36
std::vector< llvm::Value * > codegen(const Analyzer::Expr *, const bool fetch_columns, const CompilationOptions &)
Definition: IRCodegen.cpp:30
Definition: sqltypes.h:79
void unpack_none_encoded_string(CgenState *cgen_state, std::vector< llvm::Value * > &lvs)
Definition: CompareIR.cpp:456
Definition: sqldefs.h:74
HOST DEVICE EncodingType get_compression() const
Definition: sqltypes.h:399
std::shared_ptr< Analyzer::BinOper > make_eq(const std::shared_ptr< Analyzer::Expr > &lhs, const std::shared_ptr< Analyzer::Expr > &rhs, const SQLOps optype)
Definition: CompareIR.cpp:145
llvm::Value * codegenQualifierCmp(const SQLOps, const SQLQualifier, std::vector< llvm::Value * >, const Analyzer::Expr *, const CompilationOptions &)
Definition: CompareIR.cpp:589
bool g_enable_bbox_intersect_hashjoin
Definition: Execute.cpp:109
Definition: sqldefs.h:34
llvm::StructType * createStringViewStructType()
llvm::Value * codegenBoundingBoxIntersect(const SQLOps, const SQLQualifier, const std::shared_ptr< Analyzer::Expr >, const std::shared_ptr< Analyzer::Expr >, const CompilationOptions &)
Definition: CompareIR.cpp:285
llvm::CmpInst::Predicate llvm_icmp_pred(const SQLOps op_type)
Definition: CompareIR.cpp:26
llvm::Value * codegenCmp(const Analyzer::BinOper *, const CompilationOptions &)
Definition: CompareIR.cpp:230
llvm::ConstantInt * llInt(const T v) const
Definition: CgenState.h:249
#define CHECK(condition)
Definition: Logger.h:291
bool is_geometry() const
Definition: sqltypes.h:597
Definition: sqldefs.h:33
llvm::Value * codegenLogical(const Analyzer::BinOper *, const CompilationOptions &)
Definition: LogicalIR.cpp:299
uint64_t exp_to_scale(const unsigned exp)
int64_t inline_int_null_val(const SQL_TYPE_INFO &ti)
bool g_cluster
Definition: sqldefs.h:35
const Expr * get_left_operand() const
Definition: Analyzer.h:455
llvm::Value * codegenCast(const Analyzer::UOper *, const CompilationOptions &)
Definition: CastIR.cpp:21
std::string numeric_type_name(const SQLTypeInfo &ti)
Definition: Execute.h:230
Definition: sqltypes.h:72
bool is_unnest(const Analyzer::Expr *expr)
Definition: Execute.h:1677
bool is_string() const
Definition: sqltypes.h:561
const std::shared_ptr< Analyzer::Expr > get_own_right_operand() const
Definition: Analyzer.h:460
Definition: Datum.h:71
bool is_decimal() const
Definition: sqltypes.h:570
const std::shared_ptr< Analyzer::Expr > get_own_left_operand() const
Definition: Analyzer.h:457
#define VLOG(n)
Definition: Logger.h:388
std::string string_cmp_func(const SQLOps optype)
Definition: CompareIR.cpp:106
#define IS_COMPARISON(X)
Definition: sqldefs.h:61
SQLQualifier get_qualifier() const
Definition: Analyzer.h:454
const shared::StringDictKey & getStringDictKey() const
Definition: sqltypes.h:1057
Executor * executor() const
#define IS_GEO_POLY(T)
Definition: sqltypes.h:315