OmniSciDB  dfae7c3b14
ColumnIR.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2017 MapD Technologies, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "CodeGenerator.h"
18 #include "Codec.h"
19 #include "Execute.h"
20 #include "WindowContext.h"
21 
22 // Code generation routines and helpers for working with column expressions.
23 
24 namespace {
25 
26 // Return the right decoder for a given column expression. Doesn't handle
27 // variable length data. The decoder encapsulates the code generation logic.
28 std::shared_ptr<Decoder> get_col_decoder(const Analyzer::ColumnVar* col_var) {
29  const auto enc_type = col_var->get_compression();
30  const auto& ti_ = col_var->get_type_info();
31  const auto& ti = (ti_.is_column() ? ti_.get_elem_type() : ti_);
32  switch (enc_type) {
33  case kENCODING_NONE: {
34  const auto int_type = ti.is_decimal() ? decimal_to_int_type(ti) : ti.get_type();
35  switch (int_type) {
36  case kBOOLEAN:
37  return std::make_shared<FixedWidthInt>(1);
38  case kTINYINT:
39  return std::make_shared<FixedWidthInt>(1);
40  case kSMALLINT:
41  return std::make_shared<FixedWidthInt>(2);
42  case kINT:
43  return std::make_shared<FixedWidthInt>(4);
44  case kBIGINT:
45  return std::make_shared<FixedWidthInt>(8);
46  case kFLOAT:
47  return std::make_shared<FixedWidthReal>(false);
48  case kDOUBLE:
49  return std::make_shared<FixedWidthReal>(true);
50  case kTIME:
51  case kTIMESTAMP:
52  case kDATE:
53  return std::make_shared<FixedWidthInt>(8);
54  default:
55  CHECK(false);
56  }
57  }
58  case kENCODING_DICT:
59  CHECK(ti.is_string());
60  // For dictionary-encoded columns encoded on less than 4 bytes, we can use
61  // unsigned representation for double the maximum cardinality. The inline
62  // null value is going to be the maximum value of the underlying type.
63  if (ti.get_size() < ti.get_logical_size()) {
64  return std::make_shared<FixedWidthUnsigned>(ti.get_size());
65  }
66  return std::make_shared<FixedWidthInt>(ti.get_size());
67  case kENCODING_FIXED: {
68  const auto bit_width = col_var->get_comp_param();
69  CHECK_EQ(0, bit_width % 8);
70  return std::make_shared<FixedWidthInt>(bit_width / 8);
71  }
73  CHECK(ti.is_date_in_days());
74  return col_var->get_comp_param() == 16 ? std::make_shared<FixedWidthSmallDate>(2)
75  : std::make_shared<FixedWidthSmallDate>(4);
76  }
77  default:
78  abort();
79  }
80 }
81 
82 size_t get_col_bit_width(const Analyzer::ColumnVar* col_var) {
83  const auto& type_info = col_var->get_type_info();
84  return get_bit_width(type_info);
85 }
86 
88  return col_var->get_rte_idx() == -1 ? 0 : col_var->get_rte_idx();
89 }
90 
91 } // namespace
92 
93 std::vector<llvm::Value*> CodeGenerator::codegenColumn(const Analyzer::ColumnVar* col_var,
94  const bool fetch_column,
95  const CompilationOptions& co) {
96  AUTOMATIC_IR_METADATA(cgen_state_);
97  if (col_var->get_rte_idx() <= 0 ||
98  cgen_state_->outer_join_match_found_per_level_.empty() ||
99  !foundOuterJoinMatch(col_var->get_rte_idx())) {
100  return codegenColVar(col_var, fetch_column, true, co);
101  }
102  return codegenOuterJoinNullPlaceholder(col_var, fetch_column, co);
103 }
104 
105 std::vector<llvm::Value*> CodeGenerator::codegenColVar(const Analyzer::ColumnVar* col_var,
106  const bool fetch_column,
107  const bool update_query_plan,
108  const CompilationOptions& co) {
109  AUTOMATIC_IR_METADATA(cgen_state_);
110  const bool hoist_literals = co.hoist_literals;
111  auto col_id = col_var->get_column_id();
112  const int rte_idx = adjusted_range_table_index(col_var);
113  CHECK_LT(static_cast<size_t>(rte_idx), cgen_state_->frag_offsets_.size());
114  const auto catalog = executor()->getCatalog();
115  CHECK(catalog);
116  if (col_var->get_table_id() > 0) {
117  auto cd = get_column_descriptor(col_id, col_var->get_table_id(), *catalog);
118  if (cd->isVirtualCol) {
119  CHECK(cd->columnName == "rowid");
120  return {codegenRowId(col_var, co)};
121  }
122  auto col_ti = cd->columnType;
123  if (col_ti.get_physical_coord_cols() > 0) {
124  std::vector<llvm::Value*> cols;
125  for (auto i = 0; i < col_ti.get_physical_coord_cols(); i++) {
126  auto cd0 =
127  get_column_descriptor(col_id + i + 1, col_var->get_table_id(), *catalog);
128  auto col0_ti = cd0->columnType;
129  CHECK(!cd0->isVirtualCol);
130  auto col0_var = makeExpr<Analyzer::ColumnVar>(
131  col0_ti, col_var->get_table_id(), cd0->columnId, rte_idx);
132  auto col = codegenColVar(col0_var.get(), fetch_column, false, co);
133  cols.insert(cols.end(), col.begin(), col.end());
134  if (!fetch_column && plan_state_->isLazyFetchColumn(col_var)) {
135  plan_state_->columns_to_not_fetch_.insert(
136  std::make_pair(col_var->get_table_id(), col0_var->get_column_id()));
137  }
138  }
139  if (!fetch_column && plan_state_->isLazyFetchColumn(col_var)) {
140  plan_state_->columns_to_not_fetch_.insert(
141  std::make_pair(col_var->get_table_id(), col_var->get_column_id()));
142  } else {
143  plan_state_->columns_to_fetch_.insert(
144  std::make_pair(col_var->get_table_id(), col_var->get_column_id()));
145  }
146  return cols;
147  }
148  } else {
149  if (col_var->get_type_info().is_geometry()) {
150  throw std::runtime_error(
151  "Geospatial columns not supported in temporary tables yet");
152  }
153  }
154  const auto grouped_col_lv = resolveGroupedColumnReference(col_var);
155  if (grouped_col_lv) {
156  return {grouped_col_lv};
157  }
158  const int local_col_id = plan_state_->getLocalColumnId(col_var, fetch_column);
159  const auto window_func_context =
161  // only generate the decoding code once; if a column has been previously
162  // fetched in the generated IR, we'll reuse it
163  if (!window_func_context) {
164  auto it = cgen_state_->fetch_cache_.find(local_col_id);
165  if (it != cgen_state_->fetch_cache_.end()) {
166  return {it->second};
167  }
168  }
169  const auto hash_join_lhs = hashJoinLhs(col_var);
170  // Note(jclay): This has been prone to cause failures in some overlaps joins.
171  // I believe most of the issues are worked out now, but a good place to check if
172  // failures are happening.
173 
174  // Use the already fetched left-hand side of an equi-join if the types are identical.
175  // Currently, types can only be different because of different underlying dictionaries.
176  if (hash_join_lhs && hash_join_lhs->get_type_info() == col_var->get_type_info()) {
177  if (plan_state_->isLazyFetchColumn(col_var)) {
178  plan_state_->columns_to_fetch_.insert(
179  std::make_pair(col_var->get_table_id(), col_var->get_column_id()));
180  }
181  return codegen(hash_join_lhs.get(), fetch_column, co);
182  }
183  auto pos_arg = posArg(col_var);
184  if (window_func_context) {
185  pos_arg = codegenWindowPosition(window_func_context, pos_arg);
186  }
187  auto col_byte_stream = colByteStream(col_var, fetch_column, hoist_literals);
188  if (plan_state_->isLazyFetchColumn(col_var)) {
189  if (update_query_plan) {
190  plan_state_->columns_to_not_fetch_.insert(
191  std::make_pair(col_var->get_table_id(), col_var->get_column_id()));
192  }
193  if (rte_idx > 0) {
194  const auto offset = cgen_state_->frag_offsets_[rte_idx];
195  if (offset) {
196  return {cgen_state_->ir_builder_.CreateAdd(pos_arg, offset)};
197  } else {
198  return {pos_arg};
199  }
200  }
201  return {pos_arg};
202  }
203  const auto& col_ti = col_var->get_type_info();
204  if (col_ti.is_string() && col_ti.get_compression() == kENCODING_NONE) {
205  const auto varlen_str_column_lvs =
206  codegenVariableLengthStringColVar(col_byte_stream, pos_arg);
207  if (!window_func_context) {
208  auto it_ok = cgen_state_->fetch_cache_.insert(
209  std::make_pair(local_col_id, varlen_str_column_lvs));
210  CHECK(it_ok.second);
211  }
212  return varlen_str_column_lvs;
213  }
214  if (col_ti.is_array()) {
215  return {col_byte_stream};
216  }
217  if (window_func_context) {
218  return {codegenFixedLengthColVarInWindow(col_var, col_byte_stream, pos_arg)};
219  }
220  const auto fixed_length_column_lv =
221  codegenFixedLengthColVar(col_var, col_byte_stream, pos_arg);
222  auto it_ok = cgen_state_->fetch_cache_.insert(
223  std::make_pair(local_col_id, std::vector<llvm::Value*>{fixed_length_column_lv}));
224  return {it_ok.first->second};
225 }
226 
228  WindowFunctionContext* window_func_context,
229  llvm::Value* pos_arg) {
230  AUTOMATIC_IR_METADATA(cgen_state_);
231  const auto window_position = cgen_state_->emitCall(
232  "row_number_window_func",
233  {cgen_state_->llInt(reinterpret_cast<const int64_t>(window_func_context->output())),
234  pos_arg});
235  window_func_context->setRowNumber(window_position);
236  return window_position;
237 }
238 
239 // Generate code for fixed length column types (number, timestamp or date,
240 // dictionary-encoded string)
242  llvm::Value* col_byte_stream,
243  llvm::Value* pos_arg) {
244  AUTOMATIC_IR_METADATA(cgen_state_);
245  const auto decoder = get_col_decoder(col_var);
246  auto dec_val = decoder->codegenDecode(col_byte_stream, pos_arg, cgen_state_->module_);
247  cgen_state_->ir_builder_.Insert(dec_val);
248  auto dec_type = dec_val->getType();
249  llvm::Value* dec_val_cast{nullptr};
250  const auto& col_ti_ = col_var->get_type_info();
251  const auto& col_ti = (col_ti_.is_column() ? col_ti_.get_elem_type() : col_ti_);
252  if (dec_type->isIntegerTy()) {
253  auto dec_width = static_cast<llvm::IntegerType*>(dec_type)->getBitWidth();
254  auto col_width = get_col_bit_width(col_var);
255  dec_val_cast = cgen_state_->ir_builder_.CreateCast(
256  static_cast<size_t>(col_width) > dec_width ? llvm::Instruction::CastOps::SExt
257  : llvm::Instruction::CastOps::Trunc,
258  dec_val,
259  get_int_type(col_width, cgen_state_->context_));
260  if ((col_ti.get_compression() == kENCODING_FIXED ||
261  (col_ti.get_compression() == kENCODING_DICT && col_ti.get_size() < 4)) &&
262  !col_ti.get_notnull()) {
263  dec_val_cast = codgenAdjustFixedEncNull(dec_val_cast, col_ti);
264  }
265  } else {
266  CHECK_EQ(kENCODING_NONE, col_ti.get_compression());
267  CHECK(dec_type->isFloatTy() || dec_type->isDoubleTy());
268  if (dec_type->isDoubleTy()) {
269  CHECK(col_ti.get_type() == kDOUBLE);
270  } else if (dec_type->isFloatTy()) {
271  CHECK(col_ti.get_type() == kFLOAT);
272  }
273  dec_val_cast = dec_val;
274  }
275  CHECK(dec_val_cast);
276  return dec_val_cast;
277 }
278 
280  const Analyzer::ColumnVar* col_var,
281  llvm::Value* col_byte_stream,
282  llvm::Value* pos_arg) {
283  AUTOMATIC_IR_METADATA(cgen_state_);
284  const auto orig_bb = cgen_state_->ir_builder_.GetInsertBlock();
285  const auto pos_is_valid =
286  cgen_state_->ir_builder_.CreateICmpSGE(pos_arg, cgen_state_->llInt(int64_t(0)));
287  const auto pos_valid_bb = llvm::BasicBlock::Create(
288  cgen_state_->context_, "window.pos_valid", cgen_state_->current_func_);
289  const auto pos_notvalid_bb = llvm::BasicBlock::Create(
290  cgen_state_->context_, "window.pos_notvalid", cgen_state_->current_func_);
291  cgen_state_->ir_builder_.CreateCondBr(pos_is_valid, pos_valid_bb, pos_notvalid_bb);
292  cgen_state_->ir_builder_.SetInsertPoint(pos_valid_bb);
293  const auto fixed_length_column_lv =
294  codegenFixedLengthColVar(col_var, col_byte_stream, pos_arg);
295  cgen_state_->ir_builder_.CreateBr(pos_notvalid_bb);
296  cgen_state_->ir_builder_.SetInsertPoint(pos_notvalid_bb);
297  const auto window_func_call_phi =
298  cgen_state_->ir_builder_.CreatePHI(fixed_length_column_lv->getType(), 2);
299  window_func_call_phi->addIncoming(fixed_length_column_lv, pos_valid_bb);
300  const auto& col_ti = col_var->get_type_info();
301  const auto null_lv =
302  col_ti.is_fp() ? static_cast<llvm::Value*>(cgen_state_->inlineFpNull(col_ti))
303  : static_cast<llvm::Value*>(cgen_state_->inlineIntNull(col_ti));
304  window_func_call_phi->addIncoming(null_lv, orig_bb);
305  return window_func_call_phi;
306 }
307 
309  llvm::Value* col_byte_stream,
310  llvm::Value* pos_arg) {
311  AUTOMATIC_IR_METADATA(cgen_state_);
312  // real (not dictionary-encoded) strings; store the pointer to the payload
313  auto ptr_and_len =
314  cgen_state_->emitExternalCall("string_decode",
315  get_int_type(64, cgen_state_->context_),
316  {col_byte_stream, pos_arg});
317  // Unpack the pointer + length, see string_decode function.
318  auto str_lv = cgen_state_->emitCall("extract_str_ptr", {ptr_and_len});
319  auto len_lv = cgen_state_->emitCall("extract_str_len", {ptr_and_len});
320  return {ptr_and_len, str_lv, len_lv};
321 }
322 
324  const CompilationOptions& co) {
325  AUTOMATIC_IR_METADATA(cgen_state_);
326  const auto offset_lv = cgen_state_->frag_offsets_[adjusted_range_table_index(col_var)];
327  llvm::Value* start_rowid_lv{nullptr};
328  const auto& table_generation = executor()->getTableGeneration(col_var->get_table_id());
329  if (table_generation.start_rowid > 0) {
330  // Handle the multi-node case: each leaf receives a start rowid used
331  // to offset the local rowid and generate a cluster-wide unique rowid.
332  Datum d;
333  d.bigintval = table_generation.start_rowid;
334  const auto start_rowid = makeExpr<Analyzer::Constant>(kBIGINT, false, d);
335  const auto start_rowid_lvs = codegen(start_rowid.get(), kENCODING_NONE, -1, co);
336  CHECK_EQ(size_t(1), start_rowid_lvs.size());
337  start_rowid_lv = start_rowid_lvs.front();
338  }
339  auto rowid_lv = posArg(col_var);
340  if (offset_lv) {
341  rowid_lv = cgen_state_->ir_builder_.CreateAdd(rowid_lv, offset_lv);
342  } else if (col_var->get_rte_idx() > 0) {
343  auto frag_off_ptr = get_arg_by_name(cgen_state_->row_func_, "frag_row_off");
344  auto input_off_ptr = cgen_state_->ir_builder_.CreateGEP(
345  frag_off_ptr, cgen_state_->llInt(int32_t(col_var->get_rte_idx())));
346  auto rowid_offset_lv = cgen_state_->ir_builder_.CreateLoad(input_off_ptr);
347  rowid_lv = cgen_state_->ir_builder_.CreateAdd(rowid_lv, rowid_offset_lv);
348  }
349  if (table_generation.start_rowid > 0) {
350  CHECK(start_rowid_lv);
351  rowid_lv = cgen_state_->ir_builder_.CreateAdd(rowid_lv, start_rowid_lv);
352  }
353  return rowid_lv;
354 }
355 
356 namespace {
357 
358 SQLTypes get_phys_int_type(const size_t byte_sz) {
359  switch (byte_sz) {
360  case 1:
361  return kBOOLEAN;
362  // TODO: kTINYINT
363  case 2:
364  return kSMALLINT;
365  case 4:
366  return kINT;
367  case 8:
368  return kBIGINT;
369  default:
370  CHECK(false);
371  }
372  return kNULLT;
373 }
374 
375 } // namespace
376 
377 llvm::Value* CodeGenerator::codgenAdjustFixedEncNull(llvm::Value* val,
378  const SQLTypeInfo& col_ti) {
379  AUTOMATIC_IR_METADATA(cgen_state_);
380  CHECK_LT(col_ti.get_size(), col_ti.get_logical_size());
381  const auto col_phys_width = col_ti.get_size() * 8;
382  auto from_typename = "int" + std::to_string(col_phys_width) + "_t";
383  auto adjusted = cgen_state_->ir_builder_.CreateCast(
384  llvm::Instruction::CastOps::Trunc,
385  val,
386  get_int_type(col_phys_width, cgen_state_->context_));
387  if (col_ti.get_compression() == kENCODING_DICT) {
388  from_typename = "u" + from_typename;
389  llvm::Value* from_null{nullptr};
390  switch (col_ti.get_size()) {
391  case 1:
392  from_null = cgen_state_->llInt(std::numeric_limits<uint8_t>::max());
393  break;
394  case 2:
395  from_null = cgen_state_->llInt(std::numeric_limits<uint16_t>::max());
396  break;
397  default:
398  CHECK(false);
399  }
400  return cgen_state_->emitCall(
401  "cast_" + from_typename + "_to_" + numeric_type_name(col_ti) + "_nullable",
402  {adjusted, from_null, cgen_state_->inlineIntNull(col_ti)});
403  }
404  SQLTypeInfo col_phys_ti(get_phys_int_type(col_ti.get_size()),
405  col_ti.get_dimension(),
406  col_ti.get_scale(),
407  false,
409  0,
410  col_ti.get_subtype());
411  return cgen_state_->emitCall(
412  "cast_" + from_typename + "_to_" + numeric_type_name(col_ti) + "_nullable",
413  {adjusted,
414  cgen_state_->inlineIntNull(col_phys_ti),
415  cgen_state_->inlineIntNull(col_ti)});
416 }
417 
418 llvm::Value* CodeGenerator::foundOuterJoinMatch(const size_t nesting_level) const {
419  CHECK_GE(nesting_level, size_t(1));
420  CHECK_LE(nesting_level,
421  static_cast<size_t>(cgen_state_->outer_join_match_found_per_level_.size()));
422  return cgen_state_->outer_join_match_found_per_level_[nesting_level - 1];
423 }
424 
426  const Analyzer::ColumnVar* col_var,
427  const bool fetch_column,
428  const CompilationOptions& co) {
429  AUTOMATIC_IR_METADATA(cgen_state_);
430  const auto grouped_col_lv = resolveGroupedColumnReference(col_var);
431  if (grouped_col_lv) {
432  return {grouped_col_lv};
433  }
434  const auto outer_join_args_bb = llvm::BasicBlock::Create(
435  cgen_state_->context_, "outer_join_args", cgen_state_->current_func_);
436  const auto outer_join_nulls_bb = llvm::BasicBlock::Create(
437  cgen_state_->context_, "outer_join_nulls", cgen_state_->current_func_);
438  const auto phi_bb = llvm::BasicBlock::Create(
439  cgen_state_->context_, "outer_join_phi", cgen_state_->current_func_);
440  const auto outer_join_match_lv = foundOuterJoinMatch(col_var->get_rte_idx());
441  CHECK(outer_join_match_lv);
442  cgen_state_->ir_builder_.CreateCondBr(
443  outer_join_match_lv, outer_join_args_bb, outer_join_nulls_bb);
444  const auto back_from_outer_join_bb = llvm::BasicBlock::Create(
445  cgen_state_->context_, "back_from_outer_join", cgen_state_->current_func_);
446  cgen_state_->ir_builder_.SetInsertPoint(outer_join_args_bb);
447  Executor::FetchCacheAnchor anchor(cgen_state_);
448  const auto orig_lvs = codegenColVar(col_var, fetch_column, true, co);
449  cgen_state_->ir_builder_.CreateBr(phi_bb);
450  cgen_state_->ir_builder_.SetInsertPoint(outer_join_nulls_bb);
451  const auto& null_ti = col_var->get_type_info();
452  if ((null_ti.is_string() && null_ti.get_compression() == kENCODING_NONE) ||
453  null_ti.is_array() || null_ti.is_geometry()) {
454  throw std::runtime_error("Projection type " + null_ti.get_type_name() +
455  " not supported for outer joins yet");
456  }
457  const auto null_constant = makeExpr<Analyzer::Constant>(null_ti, true, Datum{0});
458  const auto null_target_lvs =
459  codegen(null_constant.get(),
460  false,
463  cgen_state_->ir_builder_.CreateBr(phi_bb);
464  CHECK_EQ(orig_lvs.size(), null_target_lvs.size());
465  cgen_state_->ir_builder_.SetInsertPoint(phi_bb);
466  std::vector<llvm::Value*> target_lvs;
467  for (size_t i = 0; i < orig_lvs.size(); ++i) {
468  const auto target_type = orig_lvs[i]->getType();
469  CHECK_EQ(target_type, null_target_lvs[i]->getType());
470  auto target_phi = cgen_state_->ir_builder_.CreatePHI(target_type, 2);
471  target_phi->addIncoming(orig_lvs[i], outer_join_args_bb);
472  target_phi->addIncoming(null_target_lvs[i], outer_join_nulls_bb);
473  target_lvs.push_back(target_phi);
474  }
475  cgen_state_->ir_builder_.CreateBr(back_from_outer_join_bb);
476  cgen_state_->ir_builder_.SetInsertPoint(back_from_outer_join_bb);
477  return target_lvs;
478 }
479 
481  const Analyzer::ColumnVar* col_var) {
482  auto col_id = col_var->get_column_id();
483  if (col_var->get_rte_idx() >= 0) {
484  return nullptr;
485  }
486  CHECK((col_id == 0) || (col_var->get_rte_idx() >= 0 && col_var->get_table_id() > 0));
487  const auto var = dynamic_cast<const Analyzer::Var*>(col_var);
488  CHECK(var);
489  col_id = var->get_varno();
490  CHECK_GE(col_id, 1);
491  if (var->get_which_row() == Analyzer::Var::kGROUPBY) {
492  CHECK_LE(static_cast<size_t>(col_id), cgen_state_->group_by_expr_cache_.size());
493  return cgen_state_->group_by_expr_cache_[col_id - 1];
494  }
495  return nullptr;
496 }
497 
498 // returns the byte stream argument and the position for the given column
500  const bool fetch_column,
501  const bool hoist_literals) {
502  CHECK_GE(cgen_state_->row_func_->arg_size(), size_t(3));
503  const auto stream_arg_name =
504  "col_buf" + std::to_string(plan_state_->getLocalColumnId(col_var, fetch_column));
505  for (auto& arg : cgen_state_->row_func_->args()) {
506  if (arg.getName() == stream_arg_name) {
507  CHECK(arg.getType() == llvm::Type::getInt8PtrTy(cgen_state_->context_));
508  return &arg;
509  }
510  }
511  CHECK(false);
512  return nullptr;
513 }
514 
515 llvm::Value* CodeGenerator::posArg(const Analyzer::Expr* expr) const {
516  AUTOMATIC_IR_METADATA(cgen_state_);
517  const auto col_var = dynamic_cast<const Analyzer::ColumnVar*>(expr);
518  if (col_var && col_var->get_rte_idx() > 0) {
519  const auto hash_pos_it =
520  cgen_state_->scan_idx_to_hash_pos_.find(col_var->get_rte_idx());
521  CHECK(hash_pos_it != cgen_state_->scan_idx_to_hash_pos_.end());
522  if (hash_pos_it->second->getType()->isPointerTy()) {
523  CHECK(hash_pos_it->second->getType()->getPointerElementType()->isIntegerTy(32));
524  llvm::Value* result = cgen_state_->ir_builder_.CreateLoad(hash_pos_it->second);
525  result = cgen_state_->ir_builder_.CreateSExt(
526  result, get_int_type(64, cgen_state_->context_));
527  return result;
528  }
529  return hash_pos_it->second;
530  }
531  for (auto& arg : cgen_state_->row_func_->args()) {
532  if (arg.getName() == "pos") {
533  CHECK(arg.getType()->isIntegerTy(64));
534  return &arg;
535  }
536  }
537  abort();
538 }
539 
541  const auto uoper = dynamic_cast<const Analyzer::UOper*>(expr);
542  if (!uoper || uoper->get_optype() != kCAST) {
543  return nullptr;
544  }
545  const auto& target_ti = uoper->get_type_info();
546  if (!target_ti.is_integer()) {
547  return nullptr;
548  }
549  return uoper->get_operand();
550 }
551 
552 std::shared_ptr<const Analyzer::Expr> CodeGenerator::hashJoinLhs(
553  const Analyzer::ColumnVar* rhs) const {
554  for (const auto& tautological_eq : plan_state_->join_info_.equi_join_tautologies_) {
555  CHECK(IS_EQUIVALENCE(tautological_eq->get_optype()));
556  if (dynamic_cast<const Analyzer::ExpressionTuple*>(
557  tautological_eq->get_left_operand())) {
558  auto lhs_col = hashJoinLhsTuple(rhs, tautological_eq.get());
559  if (lhs_col) {
560  return lhs_col;
561  }
562  } else {
563  auto eq_right_op = tautological_eq->get_right_operand();
564  if (!rhs->get_type_info().is_string()) {
565  eq_right_op = remove_cast_to_int(eq_right_op);
566  }
567  if (!eq_right_op) {
568  eq_right_op = tautological_eq->get_right_operand();
569  }
570  if (*eq_right_op == *rhs) {
571  auto eq_left_op = tautological_eq->get_left_operand();
572  if (!eq_left_op->get_type_info().is_string()) {
573  eq_left_op = remove_cast_to_int(eq_left_op);
574  }
575  if (!eq_left_op) {
576  eq_left_op = tautological_eq->get_left_operand();
577  }
578  if (eq_left_op->get_type_info().is_geometry()) {
579  // skip cast for a geospatial lhs, since the rhs is likely to be a geospatial
580  // physical col without geospatial type info
581  return nullptr;
582  }
583  const auto eq_left_op_col = dynamic_cast<const Analyzer::ColumnVar*>(eq_left_op);
584  CHECK(eq_left_op_col);
585  if (eq_left_op_col->get_rte_idx() != 0) {
586  return nullptr;
587  }
588  if (rhs->get_type_info().is_string()) {
589  return eq_left_op->deep_copy();
590  }
591  if (rhs->get_type_info().is_array()) {
592  // Note(jclay): Can this be restored from copy as above?
593  // If we fall through to the below return statement,
594  // a superfulous cast from DOUBLE[] to DOUBLE[] is made and
595  // this fails at a later stage in codegen.
596  return nullptr;
597  }
598  return makeExpr<Analyzer::UOper>(
599  rhs->get_type_info(), false, kCAST, eq_left_op->deep_copy());
600  }
601  }
602  }
603  return nullptr;
604 }
605 
606 std::shared_ptr<const Analyzer::ColumnVar> CodeGenerator::hashJoinLhsTuple(
607  const Analyzer::ColumnVar* rhs,
608  const Analyzer::BinOper* tautological_eq) const {
609  const auto lhs_tuple_expr =
610  dynamic_cast<const Analyzer::ExpressionTuple*>(tautological_eq->get_left_operand());
611  const auto rhs_tuple_expr = dynamic_cast<const Analyzer::ExpressionTuple*>(
612  tautological_eq->get_right_operand());
613  CHECK(lhs_tuple_expr && rhs_tuple_expr);
614  const auto& lhs_tuple = lhs_tuple_expr->getTuple();
615  const auto& rhs_tuple = rhs_tuple_expr->getTuple();
616  CHECK_EQ(lhs_tuple.size(), rhs_tuple.size());
617  for (size_t i = 0; i < lhs_tuple.size(); ++i) {
618  if (*rhs_tuple[i] == *rhs) {
619  const auto lhs_col =
620  std::static_pointer_cast<const Analyzer::ColumnVar>(lhs_tuple[i]);
621  return lhs_col->get_rte_idx() == 0 ? lhs_col : nullptr;
622  }
623  }
624  return nullptr;
625 }
#define CHECK_EQ(x, y)
Definition: Logger.h:205
std::shared_ptr< const Analyzer::ColumnVar > hashJoinLhsTuple(const Analyzer::ColumnVar *rhs, const Analyzer::BinOper *tautological_eq) const
Definition: ColumnIR.cpp:606
bool is_array() const
Definition: sqltypes.h:425
bool is_string() const
Definition: sqltypes.h:417
int get_column_id() const
Definition: Analyzer.h:195
const Analyzer::Expr * remove_cast_to_int(const Analyzer::Expr *expr)
Definition: ColumnIR.cpp:540
Definition: sqltypes.h:51
SQLTypes
Definition: sqltypes.h:40
llvm::Value * foundOuterJoinMatch(const size_t nesting_level) const
Definition: ColumnIR.cpp:418
std::shared_ptr< const Analyzer::Expr > hashJoinLhs(const Analyzer::ColumnVar *rhs) const
Definition: ColumnIR.cpp:552
#define IS_EQUIVALENCE(X)
Definition: sqldefs.h:67
llvm::Value * codegenRowId(const Analyzer::ColumnVar *col_var, const CompilationOptions &co)
Definition: ColumnIR.cpp:323
std::vector< llvm::Value * > codegenOuterJoinNullPlaceholder(const Analyzer::ColumnVar *col_var, const bool fetch_column, const CompilationOptions &co)
Definition: ColumnIR.cpp:425
#define CHECK_GE(x, y)
Definition: Logger.h:210
llvm::Value * codgenAdjustFixedEncNull(llvm::Value *, const SQLTypeInfo &)
Definition: ColumnIR.cpp:377
Definition: sqldefs.h:49
HOST DEVICE int get_size() const
Definition: sqltypes.h:269
virtual std::vector< llvm::Value * > codegenColumn(const Analyzer::ColumnVar *, const bool fetch_column, const CompilationOptions &)
Definition: ColumnIR.cpp:93
HOST DEVICE EncodingType get_compression() const
Definition: sqltypes.h:267
llvm::Type * get_int_type(const int width, llvm::LLVMContext &context)
std::shared_ptr< Decoder > get_col_decoder(const Analyzer::ColumnVar *col_var)
Definition: ColumnIR.cpp:28
static WindowFunctionContext * getActiveWindowFunctionContext(Executor *executor)
HOST DEVICE int get_scale() const
Definition: sqltypes.h:264
std::string to_string(char const *&&v)
int get_logical_size() const
Definition: sqltypes.h:270
size_t get_bit_width(const SQLTypeInfo &ti)
llvm::Value * get_arg_by_name(llvm::Function *func, const std::string &name)
Definition: Execute.h:129
size_t get_col_bit_width(const Analyzer::ColumnVar *col_var)
Definition: ColumnIR.cpp:82
void setRowNumber(llvm::Value *row_number)
int64_t bigintval
Definition: sqltypes.h:138
HOST DEVICE SQLTypes get_subtype() const
Definition: sqltypes.h:260
#define AUTOMATIC_IR_METADATA(CGENSTATE)
std::vector< llvm::Value * > codegenColVar(const Analyzer::ColumnVar *, const bool fetch_column, const bool update_query_plan, const CompilationOptions &)
Definition: ColumnIR.cpp:105
SQLTypes decimal_to_int_type(const SQLTypeInfo &ti)
Definition: Datum.cpp:302
#define CHECK_LT(x, y)
Definition: Logger.h:207
Definition: sqltypes.h:55
bool is_geometry() const
Definition: sqltypes.h:429
#define CHECK_LE(x, y)
Definition: Logger.h:208
EncodingType get_compression() const
Definition: Analyzer.h:197
int get_rte_idx() const
Definition: Analyzer.h:196
HOST DEVICE int get_dimension() const
Definition: sqltypes.h:261
int get_table_id() const
Definition: Analyzer.h:194
llvm::Value * codegenFixedLengthColVarInWindow(const Analyzer::ColumnVar *col_var, llvm::Value *col_byte_stream, llvm::Value *pos_arg)
Definition: ColumnIR.cpp:279
const SQLTypeInfo & get_type_info() const
Definition: Analyzer.h:78
const int8_t * output() const
llvm::Value * posArg(const Analyzer::Expr *) const
Definition: ColumnIR.cpp:515
#define CHECK(condition)
Definition: Logger.h:197
llvm::Value * colByteStream(const Analyzer::ColumnVar *col_var, const bool fetch_column, const bool hoist_literals)
Definition: ColumnIR.cpp:499
llvm::Value * codegenWindowPosition(WindowFunctionContext *window_func_context, llvm::Value *pos_arg)
Definition: ColumnIR.cpp:227
std::string numeric_type_name(const SQLTypeInfo &ti)
Definition: Execute.h:172
Definition: sqltypes.h:47
SQLTypeInfo columnType
std::vector< llvm::Value * > codegenVariableLengthStringColVar(llvm::Value *col_byte_stream, llvm::Value *pos_arg)
Definition: ColumnIR.cpp:308
llvm::Value * codegenFixedLengthColVar(const Analyzer::ColumnVar *col_var, llvm::Value *col_byte_stream, llvm::Value *pos_arg)
Definition: ColumnIR.cpp:241
SQLTypes get_phys_int_type(const size_t byte_sz)
Definition: ColumnIR.cpp:358
int adjusted_range_table_index(const Analyzer::ColumnVar *col_var)
Definition: ColumnIR.cpp:87
int get_comp_param() const
Definition: Analyzer.h:198
const ColumnDescriptor * get_column_descriptor(const int col_id, const int table_id, const Catalog_Namespace::Catalog &cat)
Definition: Execute.h:154
bool is_fp() const
Definition: sqltypes.h:421
llvm::Value * resolveGroupedColumnReference(const Analyzer::ColumnVar *)
Definition: ColumnIR.cpp:480
const Expr * get_right_operand() const
Definition: Analyzer.h:443
const Expr * get_left_operand() const
Definition: Analyzer.h:442