OmniSciDB  a5dc49c757
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
WindowFunctionIR.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 "CodegenHelper.h"
19 #include "Execute.h"
20 #include "WindowContext.h"
21 
22 llvm::Value* Executor::codegenWindowFunction(const size_t target_index,
23  const CompilationOptions& co) {
24  AUTOMATIC_IR_METADATA(cgen_state_.get());
25  CodeGenerator code_generator(this);
26 
27  const auto window_func_context =
29  target_index);
30  const auto window_func = window_func_context->getWindowFunction();
31  switch (window_func->getKind()) {
36  return code_generator.codegenWindowPosition(window_func_context,
37  code_generator.posArg(nullptr));
40  return cgen_state_->emitCall("percent_window_func",
41  {cgen_state_->llInt(reinterpret_cast<const int64_t>(
42  window_func_context->output())),
43  code_generator.posArg(nullptr)});
49  // they are always evaluated on the current frame
51  const auto& args = window_func->getArgs();
52  CHECK(!args.empty());
53  const auto arg_lvs = code_generator.codegen(args.front().get(), true, co);
54  CHECK_EQ(arg_lvs.size(), size_t(1));
55  return arg_lvs.front();
56  }
65  return codegenWindowFunctionAggregate(&code_generator, co);
73  return codegenWindowNavigationFunctionOnFrame(co);
74  default:
75  LOG(FATAL) << "Invalid window function kind";
76  }
77  return nullptr;
78 }
79 
80 namespace {
81 
83  const SQLTypeInfo& window_func_ti) {
84  std::string agg_name;
85  switch (kind) {
87  agg_name = "agg_min";
88  break;
89  }
91  agg_name = "agg_max";
92  break;
93  }
97  agg_name = "agg_sum";
98  break;
99  }
101  agg_name = "agg_count";
102  break;
103  }
105  agg_name = "agg_count_if";
106  break;
107  }
109  agg_name = "agg_sum_if";
110  break;
111  }
112  default: {
113  LOG(FATAL) << "Invalid window function kind";
114  }
115  }
116  switch (window_func_ti.get_type()) {
117  case kFLOAT: {
118  agg_name += "_float";
119  break;
120  }
121  case kDOUBLE: {
122  agg_name += "_double";
123  break;
124  }
125  default: {
126  break;
127  }
128  }
129  return agg_name;
130 }
131 
133  const auto& args = window_func->getArgs();
134  return ((window_func->getKind() == SqlWindowFunctionKind::COUNT && !args.empty()) ||
135  window_func->getKind() == SqlWindowFunctionKind::AVG)
136  ? args.front()->get_type_info()
137  : window_func->get_type_info();
138 }
139 
140 std::string get_col_type_name_by_size(const size_t size, const bool is_fp) {
141  if (is_fp) {
142  if (size == 4) {
143  return "float";
144  }
145  return "double";
146  }
147  if (size == 1) {
148  return "int8_t";
149  } else if (size == 2) {
150  return "int16_t";
151  } else if (size == 4) {
152  return "int32_t";
153  }
154  return "int64_t";
155 }
156 
157 llvm::Value* get_null_value_by_size(CgenState* cgen_state, SQLTypeInfo col_ti) {
158  if (col_ti.is_fp()) {
159  if (col_ti.get_type() == kFLOAT) {
160  return cgen_state->llFp(inline_fp_null_value<float>());
161  } else {
162  return cgen_state->llFp(inline_fp_null_value<double>());
163  }
164  } else if (col_ti.is_dict_encoded_string()) {
165  if (col_ti.get_size() == 2) {
166  return cgen_state->llInt((int16_t)inline_int_null_value<int16_t>());
167  } else {
168  CHECK_EQ(col_ti.get_size(), 4);
169  return cgen_state->llInt((int32_t)inline_int_null_value<int32_t>());
170  }
171  } else if (col_ti.is_date()) {
172  if (col_ti.get_comp_param() == 16) {
173  return cgen_state->llInt((int16_t)inline_int_null_value<int16_t>());
174  } else if (col_ti.get_comp_param() == 32) {
175  return cgen_state->llInt((int32_t)inline_int_null_value<int32_t>());
176  } else {
177  return cgen_state->llInt((int64_t)inline_int_null_value<int64_t>());
178  }
179  } else {
180  switch (col_ti.get_type()) {
181  case kBOOLEAN:
182  case kTINYINT:
183  return cgen_state->llInt((int8_t)inline_int_null_value<int8_t>());
184  case kSMALLINT:
185  if (col_ti.get_compression() == kENCODING_FIXED) {
186  return cgen_state->llInt((int16_t)(inline_fixed_encoding_null_val(col_ti)));
187  }
188  return cgen_state->llInt((int16_t)inline_int_null_value<int16_t>());
189  case kINT:
190  if (col_ti.get_compression() == kENCODING_FIXED) {
191  return cgen_state->llInt((int32_t)(inline_fixed_encoding_null_val(col_ti)));
192  }
193  return cgen_state->llInt((int32_t)inline_int_null_value<int32_t>());
194  case kTIME:
195  case kTIMESTAMP:
196  if (col_ti.get_compression() == kENCODING_FIXED) {
197  return cgen_state->llInt((int64_t)(inline_fixed_encoding_null_val(col_ti)));
198  }
199  case kBIGINT:
200  if (col_ti.get_compression() == kENCODING_FIXED) {
201  return cgen_state->llInt((int64_t)(inline_fixed_encoding_null_val(col_ti)));
202  }
203  return cgen_state->llInt((int64_t)inline_int_null_value<int64_t>());
204  case kINTERVAL_DAY_TIME:
206  case kDECIMAL:
207  case kNUMERIC:
208  return cgen_state->llInt((int64_t)inline_int_null_value<int64_t>());
209  default:
210  abort();
211  }
212  return cgen_state->llInt(inline_int_null_val(col_ti));
213  }
214 }
215 
217  SQLTypeInfo col_ti) {
218  if (col_ti.is_fp()) {
219  if (col_ti.get_type() == kFLOAT) {
220  return cgen_state->llFp(inline_fp_null_value<float>());
221  } else {
222  return cgen_state->llFp(inline_fp_null_value<double>());
223  }
224  } else {
225  llvm::Value* ret_val{nullptr};
226  if (col_ti.get_compression() == kENCODING_FIXED ||
228  ret_val = cgen_state->llInt(inline_fixed_encoding_null_val(col_ti));
229  } else {
230  ret_val = cgen_state->llInt(inline_int_null_val(col_ti));
231  }
232  size_t ret_val_col_size_in_bytes = col_ti.get_logical_size() * 8;
233  if (ret_val->getType()->getIntegerBitWidth() > ret_val_col_size_in_bytes) {
234  return cgen_state->castToTypeIn(ret_val, ret_val_col_size_in_bytes);
235  }
236  return ret_val;
237  }
238 }
239 
240 } // namespace
241 
243  const CompilationOptions& co) {
244  AUTOMATIC_IR_METADATA(cgen_state_.get());
245  const auto window_func_context =
247  const auto window_func = window_func_context->getWindowFunction();
248  const auto arg_ti = get_adjusted_window_type_info(window_func);
249  llvm::Type* aggregate_state_type =
250  arg_ti.get_type() == kFLOAT
251  ? llvm::PointerType::get(get_int_type(32, cgen_state_->context_), 0)
252  : llvm::PointerType::get(get_int_type(64, cgen_state_->context_), 0);
253  const auto aggregate_state_i64 = cgen_state_->llInt(
254  reinterpret_cast<const int64_t>(window_func_context->aggregateState()));
256  cgen_state_.get(),
257  code_generator,
258  co,
259  aggregate_state_i64,
260  aggregate_state_type,
262  .front();
263 }
264 
266  const CompilationOptions& co) {
267  AUTOMATIC_IR_METADATA(cgen_state_.get());
268  auto [reset_state_false_bb, aggregate_state] =
269  codegenWindowResetStateControlFlow(code_generator, co);
270  llvm::Value* aggregate_state_count = nullptr;
271  const auto window_func_context =
273  const auto window_func = window_func_context->getWindowFunction();
274  if (window_func->getKind() == SqlWindowFunctionKind::AVG) {
275  const auto aggregate_state_count_i64 = cgen_state_->llInt(
276  reinterpret_cast<const int64_t>(window_func_context->aggregateStateCount()));
277  const auto pi64_type =
278  llvm::PointerType::get(get_int_type(64, cgen_state_->context_), 0);
279  aggregate_state_count = CodegenUtil::createPtrWithHoistedMemoryAddr(
280  cgen_state_.get(),
281  code_generator,
282  co,
283  aggregate_state_count_i64,
284  pi64_type,
286  .front();
287  }
288  codegenWindowFunctionStateInit(code_generator, co, aggregate_state);
289  if (window_func->getKind() == SqlWindowFunctionKind::AVG) {
290  const auto count_zero = cgen_state_->llInt(int64_t(0));
291  cgen_state_->emitCall("agg_id", {aggregate_state_count, count_zero});
292  }
293  cgen_state_->ir_builder_.CreateBr(reset_state_false_bb);
294  cgen_state_->ir_builder_.SetInsertPoint(reset_state_false_bb);
296  return codegenWindowFunctionAggregateCalls(aggregate_state, co);
297 }
298 
299 std::pair<llvm::BasicBlock*, llvm::Value*> Executor::codegenWindowResetStateControlFlow(
300  CodeGenerator* code_generator,
301  const CompilationOptions& co) {
302  AUTOMATIC_IR_METADATA(cgen_state_.get());
303  const auto window_func_context =
305  auto aggregate_state = aggregateWindowStatePtr(code_generator, co);
306  const auto bitset = cgen_state_->llInt(
307  reinterpret_cast<const int64_t>(window_func_context->partitionStart()));
308  const auto bitset_lv =
310  cgen_state_.get(),
311  code_generator,
312  co,
313  bitset,
314  llvm::PointerType::get(get_int_type(8, cgen_state_->context_), 0),
316  .front();
317  const auto min_val = cgen_state_->llInt(int64_t(0));
318  const auto max_val = cgen_state_->llInt(window_func_context->elementCount() - 1);
319  const auto null_val = cgen_state_->llInt(inline_int_null_value<int64_t>());
320  const auto null_bool_val = cgen_state_->llInt<int8_t>(inline_int_null_value<int8_t>());
321  const auto reset_state =
322  code_generator->toBool(cgen_state_->emitCall("bit_is_set",
323  {bitset_lv,
324  code_generator->posArg(nullptr),
325  min_val,
326  max_val,
327  null_val,
328  null_bool_val}));
329  const auto reset_state_true_bb = llvm::BasicBlock::Create(
330  cgen_state_->context_, "reset_state.true", cgen_state_->current_func_);
331  const auto reset_state_false_bb = llvm::BasicBlock::Create(
332  cgen_state_->context_, "reset_state.false", cgen_state_->current_func_);
333  cgen_state_->ir_builder_.CreateCondBr(
334  reset_state, reset_state_true_bb, reset_state_false_bb);
335  cgen_state_->ir_builder_.SetInsertPoint(reset_state_true_bb);
336  return std::make_pair(reset_state_false_bb, aggregate_state);
337 }
338 
340  const CompilationOptions& co,
341  llvm::Value* aggregate_state) {
342  AUTOMATIC_IR_METADATA(cgen_state_.get());
343  const auto window_func_context =
345  const auto window_func = window_func_context->getWindowFunction();
346  const auto window_func_ti = get_adjusted_window_type_info(window_func);
347  const auto window_func_null_val =
348  window_func_ti.is_fp()
349  ? cgen_state_->inlineFpNull(window_func_ti)
350  : cgen_state_->castToTypeIn(cgen_state_->inlineIntNull(window_func_ti), 64);
351  llvm::Value* window_func_init_val;
352  const auto window_func_kind = window_func_context->getWindowFunction()->getKind();
353  if (window_func_kind == SqlWindowFunctionKind::COUNT ||
354  window_func_kind == SqlWindowFunctionKind::COUNT_IF) {
355  switch (window_func_ti.get_type()) {
356  case kFLOAT: {
357  window_func_init_val = cgen_state_->llFp(float(0));
358  break;
359  }
360  case kDOUBLE: {
361  window_func_init_val = cgen_state_->llFp(double(0));
362  break;
363  }
364  default: {
365  window_func_init_val = cgen_state_->llInt(int64_t(0));
366  break;
367  }
368  }
369  } else {
370  window_func_init_val = window_func_null_val;
371  }
372  const auto pi32_type =
373  llvm::PointerType::get(get_int_type(32, cgen_state_->context_), 0);
374  switch (window_func_ti.get_type()) {
375  case kDOUBLE: {
376  cgen_state_->emitCall("agg_id_double", {aggregate_state, window_func_init_val});
377  break;
378  }
379  case kFLOAT: {
380  aggregate_state =
381  cgen_state_->ir_builder_.CreateBitCast(aggregate_state, pi32_type);
382  cgen_state_->emitCall("agg_id_float", {aggregate_state, window_func_init_val});
383  break;
384  }
385  default: {
386  cgen_state_->emitCall("agg_id", {aggregate_state, window_func_init_val});
387  break;
388  }
389  }
390 }
391 
393  const CompilationOptions& co) {
394  AUTOMATIC_IR_METADATA(cgen_state_.get());
395  const auto window_func_context =
397  const auto window_func = window_func_context->getWindowFunction();
398  const auto window_func_kind = window_func->getKind();
399  const auto& args = window_func->getArgs();
400  CHECK(args.size() >= 1 && args.size() <= 3);
401  CodeGenerator code_generator(this);
402 
403  const auto target_col_ti = args.front()->get_type_info();
404  const auto target_col_size = target_col_ti.get_size();
405  const auto target_col_type_name =
406  get_col_type_name_by_size(target_col_size, target_col_ti.is_fp());
407  const auto target_col_logical_type_name = get_col_type_name_by_size(
408  window_func->get_type_info().get_size(), window_func->get_type_info().is_fp());
409 
410  // when target_column is fixed encoded, we store the actual column value by
411  // considering it, but our resultset analyzer only considers the type without encoding
412  // scheme so we handle them separately
413  auto logical_null_val_lv =
414  get_null_value_by_size(cgen_state_.get(), window_func->get_type_info());
415  auto target_col_null_val_lv =
416  get_null_value_by_size_with_encoding(cgen_state_.get(), target_col_ti);
417  if (window_func_context->elementCount() == 0) {
418  // we do not need to generate a code for an empty input table
419  return target_col_null_val_lv;
420  }
421 
422  auto current_row_pos_lv = code_generator.posArg(nullptr);
423  auto partition_index_lv = codegenCurrentPartitionIndex(
424  window_func_context, &code_generator, co, current_row_pos_lv);
425 
426  // load window function input expression; target_column
427  size_t target_col_size_in_byte = target_col_size * 8;
428  llvm::Type* col_buf_ptr_type =
429  target_col_ti.is_fp()
430  ? get_fp_type(target_col_size_in_byte, cgen_state_->context_)
431  : get_int_type(target_col_size_in_byte, cgen_state_->context_);
432  auto col_buf_type = llvm::PointerType::get(col_buf_ptr_type, 0);
433  auto target_col_buf_ptr_lv = cgen_state_->llInt(reinterpret_cast<int64_t>(
434  window_func_context->getColumnBufferForWindowFunctionExpressions().front()));
435  auto target_col_buf_lv = CodegenUtil::createPtrWithHoistedMemoryAddr(
436  cgen_state_.get(),
437  &code_generator,
438  co,
439  target_col_buf_ptr_lv,
440  col_buf_type,
442  .front();
443 
444  // prepare various buffer ptrs related to the window partition
445  auto partition_buf_ptrs = codegenLoadPartitionBuffers(
446  window_func_context, &code_generator, co, partition_index_lv);
447 
448  // null value of the ordering column
449  const auto order_key_buf_ti =
450  window_func_context->getOrderKeyColumnBufferTypes().front();
451  auto const ordering_spec = window_func->getCollation().front();
452  auto order_key_col_null_val_lv =
453  get_null_value_by_size_with_encoding(cgen_state_.get(), order_key_buf_ti);
454 
455  // load ordering column
456  auto [order_col_type_name, order_key_buf_ptr_lv] =
457  codegenLoadOrderKeyBufPtr(window_func_context, &code_generator, co);
458 
459  // null range
460  auto [null_start_pos_lv, null_end_pos_lv] =
461  codegenFrameNullRange(window_func_context, &code_generator, co, partition_index_lv);
462 
463  // compute a row index of the current row w.r.t the window frame it belongs to
464  std::string row_idx_on_frame_func = "compute_";
465  row_idx_on_frame_func += order_col_type_name;
466  row_idx_on_frame_func += ordering_spec.is_desc ? "_greater_equal" : "_less_equal";
467  row_idx_on_frame_func += "_current_row_idx_in_frame";
468  auto int64_t_one_val_lv = cgen_state_->llInt((int64_t)1);
469  auto nulls_first_lv = cgen_state_->llBool(ordering_spec.nulls_first);
470  auto cur_row_idx_in_frame_lv =
471  cgen_state_->emitCall(row_idx_on_frame_func,
472  {partition_buf_ptrs.num_elem_current_partition_lv,
473  current_row_pos_lv,
474  order_key_buf_ptr_lv,
475  partition_buf_ptrs.target_partition_rowid_ptr_lv,
476  partition_buf_ptrs.target_partition_sorted_rowid_ptr_lv,
477  order_key_col_null_val_lv,
478  nulls_first_lv,
479  null_start_pos_lv,
480  null_end_pos_lv});
481 
482  if (window_func->isMissingValueFillingFunction()) {
483  // We classify both FORWARD_FILL and BACKWARD_FILL as window frame navigate function
484  // b/c they need to determine the current row index within a sorted partition
485  // (as we did for window frame navigation functions) to compute the correct and
486  // consistent resultset Otherwise, the query result may differ per execution due to
487  // missing table ordering Now we know the current row's index in the sorted
488  // partition (cur_row_idx_in_frame_lv), so we can return by calling the runtime
489  // function with the index we computed
490  std::string func_name = "fill_" + target_col_type_name + "_missing_value";
491 
492  llvm::Value* forward_fill_lv =
493  cgen_state_->llBool(window_func_kind == SqlWindowFunctionKind::FORWARD_FILL);
494  return cgen_state_->emitCall(func_name,
495  {cur_row_idx_in_frame_lv,
496  target_col_null_val_lv,
497  target_col_buf_lv,
498  partition_buf_ptrs.num_elem_current_partition_lv,
499  partition_buf_ptrs.target_partition_rowid_ptr_lv,
500  partition_buf_ptrs.target_partition_sorted_rowid_ptr_lv,
501  forward_fill_lv});
502  }
503 
504  // compute frame bound for the current row
505  auto [frame_start_bound_expr_lv, frame_end_bound_expr_lv] =
506  codegenFrameBoundRange(window_func, code_generator, co);
507 
508  // compute frame bound for the current row
509  auto const int64_t_zero_val_lv = cgen_state_->llInt((int64_t)0);
511  frame_start_bound_expr_lv,
512  frame_end_bound_expr_lv,
513  window_func->hasRangeModeFraming() ? current_row_pos_lv : cur_row_idx_in_frame_lv,
514  nullptr,
515  window_func->hasRangeModeFraming()
516  ? int64_t_zero_val_lv
517  : partition_buf_ptrs.current_partition_start_offset_lv,
518  int64_t_zero_val_lv,
519  int64_t_one_val_lv,
520  partition_buf_ptrs.num_elem_current_partition_lv,
521  order_key_buf_ptr_lv,
522  "",
523  partition_buf_ptrs.target_partition_rowid_ptr_lv,
524  partition_buf_ptrs.target_partition_sorted_rowid_ptr_lv,
525  nulls_first_lv,
526  null_start_pos_lv,
527  null_end_pos_lv};
528  auto [frame_start_bound_lv, frame_end_bound_lv] =
529  codegenWindowFrameBounds(window_func_context,
530  window_func->getFrameStartBound(),
531  window_func->getFrameEndBound(),
532  order_key_col_null_val_lv,
534  code_generator);
535 
536  // compute the index of the current row in frame it belongs to
537  llvm::Value* modified_cur_row_idx_in_frame_lv{nullptr};
538  llvm::Value* offset_lv{nullptr};
539  switch (window_func_kind) {
541  offset_lv = cgen_state_->castToTypeIn(
542  code_generator.codegen(args[1].get(), true, co)[0], 64);
543  modified_cur_row_idx_in_frame_lv =
544  cgen_state_->ir_builder_.CreateSub(cur_row_idx_in_frame_lv, offset_lv);
545  break;
547  offset_lv = cgen_state_->castToTypeIn(
548  code_generator.codegen(args[1].get(), true, co)[0], 64);
549  modified_cur_row_idx_in_frame_lv =
550  cgen_state_->ir_builder_.CreateAdd(cur_row_idx_in_frame_lv, offset_lv);
551  break;
553  modified_cur_row_idx_in_frame_lv = frame_start_bound_lv;
554  break;
556  modified_cur_row_idx_in_frame_lv = frame_end_bound_lv;
557  break;
559  offset_lv = cgen_state_->castToTypeIn(
560  code_generator.codegen(args[1].get(), true, co)[0], 64);
561  auto candidate_offset_lv =
562  cgen_state_->ir_builder_.CreateAdd(frame_start_bound_lv, offset_lv);
563  auto out_of_frame_bound_lv =
564  cgen_state_->ir_builder_.CreateICmpSGT(candidate_offset_lv, frame_end_bound_lv);
565  modified_cur_row_idx_in_frame_lv = cgen_state_->ir_builder_.CreateSelect(
566  out_of_frame_bound_lv, cgen_state_->llInt((int64_t)-1), candidate_offset_lv);
567  break;
568  }
569  default:
570  UNREACHABLE() << "Unsupported window function to navigate a window frame.";
571  }
572  CHECK(modified_cur_row_idx_in_frame_lv);
573 
574  // get the target column value in the frame w.r.t the offset
575  std::string target_func_name = "get_";
576  target_func_name += target_col_type_name + "_value_";
577  target_func_name += target_col_logical_type_name + "_type_";
578  target_func_name += "in_frame";
579  auto res_lv =
580  cgen_state_->emitCall(target_func_name,
581  {modified_cur_row_idx_in_frame_lv,
582  frame_start_bound_lv,
583  frame_end_bound_lv,
584  target_col_buf_lv,
585  partition_buf_ptrs.target_partition_rowid_ptr_lv,
586  partition_buf_ptrs.target_partition_sorted_rowid_ptr_lv,
587  logical_null_val_lv,
588  target_col_null_val_lv});
589  if (target_col_ti.get_compression() == kENCODING_DATE_IN_DAYS) {
590  res_lv = cgen_state_->emitCall(
591  "encode_date",
592  {res_lv, logical_null_val_lv, cgen_state_->llInt((int64_t)kSecsPerDay)});
593  }
594  CHECK(res_lv);
595  return res_lv;
596 }
597 
599  const Analyzer::WindowFrame* frame_bound,
600  CodeGenerator& code_generator,
601  const CompilationOptions& co) {
602  auto needs_bound_expr_codegen = [](const Analyzer::WindowFrame* window_frame) {
603  return window_frame->getBoundType() == SqlWindowFrameBoundType::EXPR_FOLLOWING ||
604  window_frame->getBoundType() == SqlWindowFrameBoundType::EXPR_PRECEDING;
605  };
606  const auto order_col_ti = window_func->getOrderKeys().front()->get_type_info();
607  auto encode_date_col_val = [&order_col_ti, this](llvm::Value* bound_expr_lv) {
608  if (order_col_ti.get_comp_param() == 16) {
609  return cgen_state_->emitCall(
610  "fixed_width_date_encode_noinline",
611  {bound_expr_lv,
612  cgen_state_->castToTypeIn(cgen_state_->inlineIntNull(SQLTypeInfo(kSMALLINT)),
613  32),
614  cgen_state_->inlineIntNull(SQLTypeInfo(kBIGINT))});
615  } else {
616  return cgen_state_->emitCall("fixed_width_date_encode_noinline",
617  {bound_expr_lv,
618  cgen_state_->inlineIntNull(SQLTypeInfo(kINT)),
619  cgen_state_->inlineIntNull(SQLTypeInfo(kBIGINT))});
620  }
621  };
622  llvm::Value* bound_expr_lv{nullptr};
623  if (needs_bound_expr_codegen(frame_bound)) {
624  auto bound_expr = frame_bound->getBoundExpr();
625  if (auto dateadd_expr = dynamic_cast<const Analyzer::DateaddExpr*>(bound_expr)) {
626  if (dateadd_expr->get_datetime_expr()->get_type_info().is_encoded_timestamp()) {
627  dateadd_expr->set_fixed_encoding_null_val();
628  }
629  }
630  auto bound_expr_lvs = code_generator.codegen(bound_expr, true, co);
631  bound_expr_lv = bound_expr_lvs.front();
632  if (order_col_ti.is_date() && window_func->hasRangeModeFraming()) {
633  if (g_cluster) {
634  throw std::runtime_error(
635  "Range mode with date type ordering column is not supported yet.");
636  }
637  bound_expr_lv = encode_date_col_val(bound_expr_lv);
638  }
639  if (frame_bound->getBoundExpr()->get_type_info().get_size() != 8) {
640  bound_expr_lv = cgen_state_->castToTypeIn(bound_expr_lv, 64);
641  }
642  } else {
643  bound_expr_lv = cgen_state_->llInt((int64_t)-1);
644  }
645  CHECK(bound_expr_lv);
646  return bound_expr_lv;
647 }
648 
649 llvm::Value* Executor::codegenFrameBound(bool for_start_bound,
650  bool for_range_mode,
651  bool for_window_frame_naviation,
652  const Analyzer::WindowFrame* frame_bound,
653  bool is_timestamp_type_frame,
654  llvm::Value* order_key_null_val,
656  const auto bound_type = frame_bound->getBoundType();
657  auto adjust_frame_end_bound = [&](llvm::Value* target_bound_lv) {
658  return cgen_state_->ir_builder_.CreateSub(target_bound_lv, args.int64_t_one_val_lv);
659  };
661  CHECK(for_start_bound) << "frame end cannot be UNBOUNDED PRECEDING";
662  return args.int64_t_zero_val_lv;
663  } else if (bound_type == SqlWindowFrameBoundType::UNBOUNDED_FOLLOWING) {
664  CHECK(!for_start_bound) << "frame start cannot be UNBOUNDED FOLLOWING";
665  // adjust frame bound w.r.t the open frame interval if necessary
666  return for_window_frame_naviation
667  ? adjust_frame_end_bound(args.num_elem_current_partition_lv)
669  }
670  std::vector<llvm::Value*> func_args;
671  std::string op_name =
672  bound_type == SqlWindowFrameBoundType::EXPR_FOLLOWING ? "add" : "sub";
673  if (!for_range_mode) {
674  llvm::Value* current_row_bound_expr_lv{nullptr};
675  if (for_window_frame_naviation) {
676  // we already know a current row's index in (ordered) window frame in this case
677  auto bound_expr =
678  for_start_bound ? args.frame_start_bound_expr_lv : args.frame_end_bound_expr_lv;
679  if (bound_type == SqlWindowFrameBoundType::EXPR_FOLLOWING) {
680  current_row_bound_expr_lv =
681  cgen_state_->ir_builder_.CreateAdd(args.current_row_pos_lv, bound_expr);
682  } else if (bound_type == SqlWindowFrameBoundType::EXPR_PRECEDING) {
683  current_row_bound_expr_lv =
684  cgen_state_->ir_builder_.CreateSub(args.current_row_pos_lv, bound_expr);
685  } else {
687  current_row_bound_expr_lv = args.current_row_pos_lv;
688  }
689  // adjust frame bound w.r.t the open frame interval
690  if (for_start_bound) {
691  return cgen_state_->ir_builder_.CreateSelect(
692  cgen_state_->ir_builder_.CreateICmpSLT(current_row_bound_expr_lv,
693  args.int64_t_zero_val_lv),
694  args.int64_t_zero_val_lv,
695  current_row_bound_expr_lv);
696  } else {
697  return cgen_state_->ir_builder_.CreateSelect(
698  cgen_state_->ir_builder_.CreateICmpSGE(current_row_bound_expr_lv,
700  adjust_frame_end_bound(args.num_elem_current_partition_lv),
701  current_row_bound_expr_lv);
702  }
703  } else {
704  std::string func_class = for_start_bound ? "start" : "end";
705  auto const func_name = "compute_row_mode_" + func_class + "_index_" + op_name;
706  func_args = prepareRowModeFuncArgs(for_start_bound, bound_type, args);
707  current_row_bound_expr_lv = cgen_state_->emitCall(func_name, func_args);
708  }
709  return current_row_bound_expr_lv;
710  } else {
711  std::string func_class = for_start_bound ? "lower" : "upper";
712  auto const func_name = getFramingFuncName(
713  func_class,
714  args.order_type_col_name,
715  op_name,
716  bound_type != SqlWindowFrameBoundType::CURRENT_ROW && is_timestamp_type_frame);
717  func_args = prepareRangeModeFuncArgs(
718  for_start_bound, frame_bound, is_timestamp_type_frame, order_key_null_val, args);
719  auto frame_bound_lv = cgen_state_->emitCall(func_name, func_args);
720  if (!for_start_bound && for_window_frame_naviation) {
721  // adjust frame end bound w.r.t the open frame interval
722  frame_bound_lv = cgen_state_->ir_builder_.CreateSelect(
723  cgen_state_->ir_builder_.CreateICmpSGE(frame_bound_lv,
725  adjust_frame_end_bound(args.num_elem_current_partition_lv),
726  frame_bound_lv);
727  }
728  return frame_bound_lv;
729  }
730 }
731 
733  WindowFunctionContext* window_func_context) const {
734  const auto window_func = window_func_context->getWindowFunction();
735  return window_func->getOrderKeys().front()->get_type_info();
736 }
737 
738 size_t Executor::getOrderKeySize(WindowFunctionContext* window_func_context) const {
739  const auto order_key_size = getFirstOrderColTypeInfo(window_func_context).get_size();
740  return order_key_size;
741 }
742 
744  WindowFunctionContext* window_func_context) const {
745  auto const order_key_size = getOrderKeySize(window_func_context);
746  auto const order_key_ptr =
747  window_func_context->getWindowFunction()->getOrderKeys().front();
748  CHECK(order_key_ptr);
749  return get_col_type_name_by_size(order_key_size,
750  order_key_ptr->get_type_info().is_fp());
751 }
752 
754  WindowFunctionContext* window_func_context,
755  CodeGenerator& code_generator,
757  llvm::Value* current_col_value_ptr_lv{nullptr};
758  const auto order_key_size_in_byte = getOrderKeySize(window_func_context) * 8;
759  auto const order_key_ptr =
760  window_func_context->getWindowFunction()->getOrderKeys().front();
761  CHECK(order_key_ptr);
762  auto const order_col_ti = order_key_ptr->get_type_info();
763  auto const order_col_llvm_type =
764  order_col_ti.is_fp() ? get_fp_type(order_key_size_in_byte, cgen_state_->context_)
765  : get_int_type(order_key_size_in_byte, cgen_state_->context_);
766  if (!window_func_context->getWindowFunction()->isFrameNavigateWindowFunction()) {
767  auto rowid_in_partition_lv = code_generator.codegenWindowPosition(
768  window_func_context, args.current_row_pos_lv);
769  current_col_value_ptr_lv = cgen_state_->ir_builder_.CreateGEP(
770  order_col_llvm_type, args.order_key_buf_ptr_lv, rowid_in_partition_lv);
771  } else {
772  current_col_value_ptr_lv = cgen_state_->ir_builder_.CreateGEP(
773  order_col_llvm_type, args.order_key_buf_ptr_lv, args.current_row_pos_lv);
774  }
775  return cgen_state_->ir_builder_.CreateLoad(
776  current_col_value_ptr_lv->getType()->getPointerElementType(),
777  current_col_value_ptr_lv,
778  "current_col_value");
779 }
780 
782  const WindowFunctionContext* window_func_context,
783  CodeGenerator* code_generator,
784  const CompilationOptions& co,
785  llvm::Value* current_row_pos_lv) {
786  const auto pi64_type =
787  llvm::PointerType::get(get_int_type(64, cgen_state_->context_), 0);
788  const auto pi32_type =
789  llvm::PointerType::get(get_int_type(32, cgen_state_->context_), 0);
790  auto row_pos_lv = current_row_pos_lv;
791  if (window_func_context->getWindowFunction()->isFrameNavigateWindowFunction()) {
792  // `current_row_pos_lv` indicates the index of the current row, but to figure out
793  // it's index of window partition it belongs to, we need a special approach
794  // especially for window framing navigation function for instance, when we have
795  // five rows having two columns pc and val such as (2,1), (2,2), (2,3), (1,1),
796  // (1,2), we build a OneToMany Perfect Hash Table as: offset: 0 2 / count: 2 3 /
797  // payload: i1, i2, i3, i4, i5 where i1 ~ i3 and i4 ~ i5 are rows for partition 1
798  // (i.e., pc = 1) and 2 (i.e., prc = 2), respectively. But when processing the first
799  // row (2, 1), the original `current_row_pos_lv` stands for zero so computing which
800  // partitions it belongs to is hard unless hashing the value at runtime. Even if we
801  // do hash, we cannot know the exact hash slot unless we do binary + linear searches
802  // multiple times (via payload buffer and the ordered payload buffer) i.e., when the
803  // row (1,2) is assigned to the partition[4], we cannot find the hash slot index '4'
804  // by using `current_row_pos_lv` unless doing a costly operation like a linear
805  // search over the entire window partition Instead, we collect a hash slot that each
806  // row is assigned to and keep this info at the payload buffer
807  // `hash_slot_idx_ptr_lv` and use it for computing window frame navigation functions
808  auto* const hash_slot_idx_ptr =
809  window_func_context->payload() + window_func_context->elementCount();
810  auto hash_slot_idx_buf_lv =
811  cgen_state_->llInt(reinterpret_cast<int64_t>(hash_slot_idx_ptr));
812  auto hash_slot_idx_ptr_lv = CodegenUtil::createPtrWithHoistedMemoryAddr(
813  cgen_state_.get(),
814  code_generator,
815  co,
816  hash_slot_idx_buf_lv,
817  pi32_type,
819  .front();
820  auto hash_slot_idx_load_lv = cgen_state_->ir_builder_.CreateGEP(
821  hash_slot_idx_ptr_lv->getType()->getPointerElementType(),
822  hash_slot_idx_ptr_lv,
823  current_row_pos_lv);
824  row_pos_lv = cgen_state_->castToTypeIn(
825  cgen_state_->ir_builder_.CreateLoad(
826  hash_slot_idx_load_lv->getType()->getPointerElementType(),
827  hash_slot_idx_load_lv,
828  "cur_row_hash_slot_idx"),
829  64);
830  }
831  auto partition_count_lv = cgen_state_->llInt(window_func_context->partitionCount());
832  auto partition_num_count_buf_lv = cgen_state_->llInt(
833  reinterpret_cast<int64_t>(window_func_context->partitionNumCountBuf()));
834  auto partition_num_count_ptr_lv = CodegenUtil::createPtrWithHoistedMemoryAddr(
835  cgen_state_.get(),
836  code_generator,
837  co,
838  partition_num_count_buf_lv,
839  pi64_type,
841  .front();
842  return cgen_state_->emitCall(
843  "compute_int64_t_lower_bound",
844  {partition_count_lv, row_pos_lv, partition_num_count_ptr_lv});
845 }
846 
847 std::string Executor::getFramingFuncName(const std::string& bound_type,
848  const std::string& order_col_type,
849  const std::string& op_type,
850  bool for_timestamp_type) const {
851  auto target_val_type = for_timestamp_type ? "int64_t" : order_col_type;
852  auto null_type = for_timestamp_type ? "int64_t" : order_col_type;
853  return "range_mode_" + target_val_type + "_" + order_col_type + "_" + null_type + "_" +
854  op_type + "_frame_" + bound_type + "_bound";
855 }
856 
857 std::vector<llvm::Value*> Executor::prepareRowModeFuncArgs(
858  bool for_start_bound,
859  SqlWindowFrameBoundType bound_type,
860  const WindowFrameBoundFuncArgs& args) const {
861  std::vector<llvm::Value*> frame_args{args.current_row_pos_lv,
863  if (bound_type == SqlWindowFrameBoundType::CURRENT_ROW) {
864  frame_args.push_back(args.int64_t_zero_val_lv);
865  } else {
866  frame_args.push_back(for_start_bound ? args.frame_start_bound_expr_lv
867  : args.frame_end_bound_expr_lv);
868  if (bound_type == SqlWindowFrameBoundType::EXPR_FOLLOWING) {
869  frame_args.push_back(args.num_elem_current_partition_lv);
870  }
871  }
872  return frame_args;
873 }
874 
875 std::vector<llvm::Value*> Executor::prepareRangeModeFuncArgs(
876  bool for_start_bound,
877  const Analyzer::WindowFrame* frame_bound,
878  bool is_timestamp_type_frame,
879  llvm::Value* order_key_null_val,
880  const WindowFrameBoundFuncArgs& args) const {
881  llvm::Value* bound_expr_lv =
882  for_start_bound ? args.frame_start_bound_expr_lv : args.frame_end_bound_expr_lv;
883  llvm::Value* target_val_lv =
884  frame_bound->isCurrentRowBound() || !is_timestamp_type_frame
885  ? args.current_col_value_lv
886  : bound_expr_lv;
887  llvm::Value* frame_bound_val_lv =
888  frame_bound->isCurrentRowBound() || is_timestamp_type_frame
889  ? args.int64_t_zero_val_lv
890  : bound_expr_lv;
891  std::vector<llvm::Value*> frame_args{args.num_elem_current_partition_lv,
892  target_val_lv,
896  frame_bound_val_lv,
897  order_key_null_val,
898  args.nulls_first_lv,
899  args.null_start_pos_lv,
900  args.null_end_pos_lv};
901  return frame_args;
902 }
903 
904 std::pair<llvm::Value*, llvm::Value*> Executor::codegenFrameNullRange(
905  WindowFunctionContext* window_func_context,
906  CodeGenerator* code_generator,
907  const CompilationOptions& co,
908  llvm::Value* partition_index_lv) const {
909  const auto pi64_type =
910  llvm::PointerType::get(get_int_type(64, cgen_state_->context_), 0);
911  const auto null_start_pos_buf = cgen_state_->llInt(
912  reinterpret_cast<int64_t>(window_func_context->getNullValueStartPos()));
913  const auto null_start_pos_buf_ptr = CodegenUtil::createPtrWithHoistedMemoryAddr(
914  cgen_state_.get(),
915  code_generator,
916  co,
917  null_start_pos_buf,
918  pi64_type,
920  .front();
921  const auto null_start_pos_ptr =
922  cgen_state_->ir_builder_.CreateGEP(get_int_type(64, cgen_state_->context_),
923  null_start_pos_buf_ptr,
924  partition_index_lv);
925  auto null_start_pos_lv = cgen_state_->ir_builder_.CreateLoad(
926  null_start_pos_ptr->getType()->getPointerElementType(),
927  null_start_pos_ptr,
928  "null_start_pos");
929  const auto null_end_pos_buf = cgen_state_->llInt(
930  reinterpret_cast<int64_t>(window_func_context->getNullValueEndPos()));
931  const auto null_end_pos_buf_ptr = CodegenUtil::createPtrWithHoistedMemoryAddr(
932  cgen_state_.get(),
933  code_generator,
934  co,
935  null_end_pos_buf,
936  pi64_type,
938  .front();
939  const auto null_end_pos_ptr = cgen_state_->ir_builder_.CreateGEP(
940  get_int_type(64, cgen_state_->context_), null_end_pos_buf_ptr, partition_index_lv);
941  auto null_end_pos_lv = cgen_state_->ir_builder_.CreateLoad(
942  null_end_pos_ptr->getType()->getPointerElementType(),
943  null_end_pos_ptr,
944  "null_end_pos");
945  return std::make_pair(null_start_pos_lv, null_end_pos_lv);
946 }
947 
948 std::pair<std::string, llvm::Value*> Executor::codegenLoadOrderKeyBufPtr(
949  WindowFunctionContext* window_func_context,
950  CodeGenerator* code_generator,
951  const CompilationOptions& co) const {
952  auto const order_key_ti =
953  window_func_context->getWindowFunction()->getOrderKeys().front()->get_type_info();
954  auto const order_key_size = order_key_ti.get_size();
955  auto const order_col_type_name = get_col_type_name_by_size(
956  order_key_size,
957  window_func_context->getOrderKeyColumnBufferTypes().front().is_fp());
958  size_t order_key_size_in_byte = order_key_size * 8;
959  auto const order_key_type =
960  order_key_ti.is_fp() ? get_fp_type(order_key_size_in_byte, cgen_state_->context_)
961  : get_int_type(order_key_size_in_byte, cgen_state_->context_);
962  auto const order_key_buf_type = llvm::PointerType::get(order_key_type, 0);
963  auto const order_key_buf = cgen_state_->llInt(
964  reinterpret_cast<int64_t>(window_func_context->getOrderKeyColumnBuffers().front()));
965  auto const order_key_buf_ptr_lv = CodegenUtil::createPtrWithHoistedMemoryAddr(
966  cgen_state_.get(),
967  code_generator,
968  co,
969  order_key_buf,
970  order_key_buf_type,
972  .front();
973  return std::make_pair(order_col_type_name, order_key_buf_ptr_lv);
974 }
975 
977  WindowFunctionContext* window_func_context,
978  CodeGenerator* code_generator,
979  const CompilationOptions& co,
980  llvm::Value* partition_index_lv) const {
981  WindowPartitionBufferPtrs bufferPtrs;
982  const auto pi64_type =
983  llvm::PointerType::get(get_int_type(64, cgen_state_->context_), 0);
984  const auto pi32_type =
985  llvm::PointerType::get(get_int_type(32, cgen_state_->context_), 0);
986 
987  // partial sum of # elems of partitions
988  auto partition_start_offset_buf_lv = cgen_state_->llInt(
989  reinterpret_cast<int64_t>(window_func_context->partitionStartOffset()));
990  auto partition_start_offset_ptr_lv = CodegenUtil::createPtrWithHoistedMemoryAddr(
991  cgen_state_.get(),
992  code_generator,
993  co,
994  partition_start_offset_buf_lv,
995  pi64_type,
997  .front();
998 
999  // get start offset of the current partition
1000  auto current_partition_start_offset_ptr_lv =
1001  cgen_state_->ir_builder_.CreateGEP(get_int_type(64, cgen_state_->context_),
1002  partition_start_offset_ptr_lv,
1003  partition_index_lv);
1004  bufferPtrs.current_partition_start_offset_lv = cgen_state_->ir_builder_.CreateLoad(
1005  current_partition_start_offset_ptr_lv->getType()->getPointerElementType(),
1006  current_partition_start_offset_ptr_lv);
1007 
1008  // row_id buf of the current partition
1009  const auto partition_rowid_buf_lv =
1010  cgen_state_->llInt(reinterpret_cast<int64_t>(window_func_context->payload()));
1011  const auto partition_rowid_ptr_lv = CodegenUtil::createPtrWithHoistedMemoryAddr(
1012  cgen_state_.get(),
1013  code_generator,
1014  co,
1015  partition_rowid_buf_lv,
1016  pi32_type,
1018  .front();
1019  bufferPtrs.target_partition_rowid_ptr_lv =
1020  cgen_state_->ir_builder_.CreateGEP(get_int_type(32, cgen_state_->context_),
1021  partition_rowid_ptr_lv,
1023 
1024  // row_id buf of ordered current partition
1025  const auto sorted_rowid_lv = cgen_state_->llInt(
1026  reinterpret_cast<int64_t>(window_func_context->sortedPartition()));
1027  const auto sorted_rowid_ptr_lv = CodegenUtil::createPtrWithHoistedMemoryAddr(
1028  cgen_state_.get(),
1029  code_generator,
1030  co,
1031  sorted_rowid_lv,
1032  pi64_type,
1034  .front();
1036  cgen_state_->ir_builder_.CreateGEP(get_int_type(64, cgen_state_->context_),
1037  sorted_rowid_ptr_lv,
1039 
1040  // # elems per partition
1041  const auto partition_count_buf =
1042  cgen_state_->llInt(reinterpret_cast<int64_t>(window_func_context->counts()));
1043  auto partition_count_buf_ptr_lv = CodegenUtil::createPtrWithHoistedMemoryAddr(
1044  cgen_state_.get(),
1045  code_generator,
1046  co,
1047  partition_count_buf,
1048  pi32_type,
1050  .front();
1051 
1052  // # elems of the given partition
1053  const auto num_elem_current_partition_ptr =
1054  cgen_state_->ir_builder_.CreateGEP(get_int_type(32, cgen_state_->context_),
1055  partition_count_buf_ptr_lv,
1056  partition_index_lv);
1057  bufferPtrs.num_elem_current_partition_lv = cgen_state_->castToTypeIn(
1058  cgen_state_->ir_builder_.CreateLoad(
1059  num_elem_current_partition_ptr->getType()->getPointerElementType(),
1060  num_elem_current_partition_ptr),
1061  64);
1062  return bufferPtrs;
1063 }
1064 
1065 std::pair<llvm::Value*, llvm::Value*> Executor::codegenFrameBoundRange(
1066  const Analyzer::WindowFunction* window_func,
1067  CodeGenerator& code_generator,
1068  const CompilationOptions& co) {
1069  const auto frame_start_bound = window_func->getFrameStartBound();
1070  const auto frame_end_bound = window_func->getFrameEndBound();
1071  auto frame_start_bound_expr_lv =
1072  codegenFrameBoundExpr(window_func, frame_start_bound, code_generator, co);
1073  auto frame_end_bound_expr_lv =
1074  codegenFrameBoundExpr(window_func, frame_end_bound, code_generator, co);
1075  CHECK(frame_start_bound_expr_lv);
1076  CHECK(frame_end_bound_expr_lv);
1077  return std::make_pair(frame_start_bound_expr_lv, frame_end_bound_expr_lv);
1078 }
1079 
1080 std::pair<llvm::Value*, llvm::Value*> Executor::codegenWindowFrameBounds(
1081  WindowFunctionContext* window_func_context,
1082  const Analyzer::WindowFrame* frame_start_bound,
1083  const Analyzer::WindowFrame* frame_end_bound,
1084  llvm::Value* order_key_col_null_val_lv,
1086  CodeGenerator& code_generator) {
1087  const auto window_func = window_func_context->getWindowFunction();
1088  CHECK(window_func);
1089  const auto is_timestamp_type_frame = frame_start_bound->hasTimestampTypeFrameBound() ||
1090  frame_end_bound->hasTimestampTypeFrameBound();
1091 
1092  if (window_func->hasRangeModeFraming()) {
1093  CHECK(window_func_context->getOrderKeyColumnBuffers().size() == 1);
1094  CHECK(window_func->getOrderKeys().size() == 1UL);
1095  CHECK(window_func_context->getOrderKeyColumnBuffers().size() == 1UL);
1096  args.order_type_col_name = getOrderKeyTypeName(window_func_context);
1097  args.current_col_value_lv =
1098  codegenLoadCurrentValueFromColBuf(window_func_context, code_generator, args);
1099  }
1100 
1101  auto get_order_key_null_val = [is_timestamp_type_frame,
1102  &order_key_col_null_val_lv,
1103  this](const Analyzer::WindowFrame* frame_bound) {
1104  return is_timestamp_type_frame && !frame_bound->isCurrentRowBound()
1105  ? cgen_state_->castToTypeIn(order_key_col_null_val_lv, 64)
1106  : order_key_col_null_val_lv;
1107  };
1108  auto frame_start_bound_lv =
1109  codegenFrameBound(true,
1110  window_func->hasRangeModeFraming(),
1111  window_func->isFrameNavigateWindowFunction(),
1112  frame_start_bound,
1113  is_timestamp_type_frame,
1114  get_order_key_null_val(frame_start_bound),
1115  args);
1116  auto frame_end_bound_lv =
1117  codegenFrameBound(false,
1118  window_func->hasRangeModeFraming(),
1119  window_func->isFrameNavigateWindowFunction(),
1120  frame_end_bound,
1121  is_timestamp_type_frame,
1122  get_order_key_null_val(frame_end_bound),
1123  args);
1124  CHECK(frame_start_bound_lv);
1125  CHECK(frame_end_bound_lv);
1126  return std::make_pair(frame_start_bound_lv, frame_end_bound_lv);
1127 }
1128 
1129 llvm::Value* Executor::codegenWindowFunctionAggregateCalls(llvm::Value* aggregate_state,
1130  const CompilationOptions& co) {
1131  AUTOMATIC_IR_METADATA(cgen_state_.get());
1132  const auto window_func_context =
1134  const auto window_func = window_func_context->getWindowFunction();
1135  const auto window_func_ti = get_adjusted_window_type_info(window_func);
1136  const auto window_func_null_val =
1137  window_func_ti.is_fp()
1138  ? cgen_state_->inlineFpNull(window_func_ti)
1139  : cgen_state_->castToTypeIn(cgen_state_->inlineIntNull(window_func_ti), 64);
1140  if (window_func_context->elementCount() == 0) {
1141  // we do not need to generate a code for an empty input table
1142  return window_func->getKind() == SqlWindowFunctionKind::AVG
1143  ? cgen_state_->inlineFpNull(SQLTypeInfo(SQLTypes::kDOUBLE))
1144  : window_func_null_val;
1145  }
1146  const auto& args = window_func->getArgs();
1147  CodeGenerator code_generator(this);
1148  if (window_func_context->needsToBuildAggregateTree()) {
1149  // compute an aggregated value for each row of the window frame by using segment
1150  // tree when constructing a window context, we build a necessary segment tree (so
1151  // called `aggregate tree`) to query the aggregated value of the specific window
1152  // frame
1153  const auto pi64_type =
1154  llvm::PointerType::get(get_int_type(64, cgen_state_->context_), 0);
1155  const auto ppi64_type = llvm::PointerType::get(
1156  llvm::PointerType::get(get_int_type(64, cgen_state_->context_), 0), 0);
1157 
1158  auto [frame_start_bound_expr_lv, frame_end_bound_expr_lv] =
1159  codegenFrameBoundRange(window_func, code_generator, co);
1160 
1161  // compute aggregated value over the computed frame range
1162  auto current_row_pos_lv = code_generator.posArg(nullptr);
1163  auto partition_index_lv = codegenCurrentPartitionIndex(
1164  window_func_context, &code_generator, co, current_row_pos_lv);
1165 
1166  // ordering column buffer
1167  const auto target_col_ti = args.front()->get_type_info();
1168  const auto target_col_size = target_col_ti.get_size();
1169  const auto col_type_name =
1170  get_col_type_name_by_size(target_col_size, target_col_ti.is_fp());
1171 
1172  const auto partition_buf_ptrs = codegenLoadPartitionBuffers(
1173  window_func_context, &code_generator, co, partition_index_lv);
1174 
1175  auto [order_col_type_name, order_key_buf_ptr_lv] =
1176  codegenLoadOrderKeyBufPtr(window_func_context, &code_generator, co);
1177 
1178  // null value of the ordering column
1179  const auto order_key_buf_ti =
1180  window_func_context->getOrderKeyColumnBufferTypes().front();
1181  auto const ordering_spec = window_func->getCollation().front();
1182  llvm::Value* order_key_col_null_val_lv{nullptr};
1183  switch (order_key_buf_ti.get_type()) {
1184  case kDATE:
1185  case kTIMESTAMP:
1186  case kTIME: {
1187  if (order_key_buf_ti.get_compression() == kENCODING_FIXED ||
1188  order_key_buf_ti.get_compression() == kENCODING_DATE_IN_DAYS) {
1189  auto null_val = inline_fixed_encoding_null_val(order_key_buf_ti);
1190  order_key_col_null_val_lv = cgen_state_->llInt((int32_t)null_val);
1191  break;
1192  }
1193  }
1194  default: {
1195  order_key_col_null_val_lv = cgen_state_->inlineNull(order_key_buf_ti);
1196  break;
1197  }
1198  }
1199 
1200  auto [null_start_pos_lv, null_end_pos_lv] = codegenFrameNullRange(
1201  window_func_context, &code_generator, co, partition_index_lv);
1202  auto nulls_first_lv = cgen_state_->llBool(ordering_spec.nulls_first);
1203 
1205  frame_start_bound_expr_lv,
1206  frame_end_bound_expr_lv,
1207  current_row_pos_lv,
1208  nullptr,
1209  partition_buf_ptrs.current_partition_start_offset_lv,
1210  cgen_state_->llInt((int64_t)0),
1211  cgen_state_->llInt((int64_t)1),
1212  partition_buf_ptrs.num_elem_current_partition_lv,
1213  order_key_buf_ptr_lv,
1214  "",
1215  partition_buf_ptrs.target_partition_rowid_ptr_lv,
1216  partition_buf_ptrs.target_partition_sorted_rowid_ptr_lv,
1217  nulls_first_lv,
1218  null_start_pos_lv,
1219  null_end_pos_lv};
1220  auto [frame_start_bound_lv, frame_end_bound_lv] =
1221  codegenWindowFrameBounds(window_func_context,
1222  window_func->getFrameStartBound(),
1223  window_func->getFrameEndBound(),
1224  order_key_col_null_val_lv,
1226  code_generator);
1227 
1228  // codegen to send a query with frame bound to aggregate tree searcher
1229  llvm::ConstantInt* aggregation_trees_lv{nullptr};
1230  llvm::Value* invalid_val_lv{nullptr};
1231  llvm::Value* null_val_lv{nullptr};
1232  std::string aggregation_tree_search_func_name{"search_"};
1233  std::string aggregation_tree_getter_func_name{"get_"};
1234 
1235  // prepare null values and aggregate_tree getter and searcher depending on
1236  // a type of the ordering column
1237  auto agg_expr_ti = args.front()->get_type_info();
1238  if (agg_expr_ti.is_fp()) {
1239  if (window_func->getKind() == SqlWindowFunctionKind::MIN) {
1240  invalid_val_lv = cgen_state_->llFp(std::numeric_limits<double>::max());
1241  } else if (window_func->getKind() == SqlWindowFunctionKind::MAX) {
1242  invalid_val_lv = cgen_state_->llFp(std::numeric_limits<double>::lowest());
1243  } else {
1244  invalid_val_lv = cgen_state_->llFp((double)0);
1245  }
1246  null_val_lv = cgen_state_->inlineFpNull(SQLTypeInfo(kDOUBLE));
1247  aggregation_tree_search_func_name += "double";
1248  aggregation_tree_getter_func_name += "double";
1249  } else {
1250  if (window_func->getKind() == SqlWindowFunctionKind::MIN) {
1251  invalid_val_lv = cgen_state_->llInt(std::numeric_limits<int64_t>::max());
1252  } else if (window_func->getKind() == SqlWindowFunctionKind::MAX) {
1253  invalid_val_lv = cgen_state_->llInt(std::numeric_limits<int64_t>::lowest());
1254  } else {
1255  invalid_val_lv = cgen_state_->llInt((int64_t)0);
1256  }
1257  null_val_lv = cgen_state_->llInt(inline_int_null_value<int64_t>());
1258  aggregation_tree_search_func_name += "int64_t";
1259  aggregation_tree_getter_func_name += "integer";
1260  }
1261 
1262  // derived aggregation has a different code path
1263  if (window_func->getKind() == SqlWindowFunctionKind::AVG) {
1264  aggregation_tree_search_func_name += "_derived";
1265  aggregation_tree_getter_func_name += "_derived";
1266  }
1267 
1268  // get a buffer holding aggregate trees for each partition
1269  if (agg_expr_ti.is_fp()) {
1270  if (window_func->getKind() == SqlWindowFunctionKind::AVG) {
1271  aggregation_trees_lv = cgen_state_->llInt(reinterpret_cast<int64_t>(
1272  window_func_context->getDerivedAggregationTreesForDoubleTypeWindowExpr()));
1273  } else {
1274  aggregation_trees_lv = cgen_state_->llInt(reinterpret_cast<int64_t>(
1275  window_func_context->getAggregationTreesForDoubleTypeWindowExpr()));
1276  }
1277  } else {
1278  if (window_func->getKind() == SqlWindowFunctionKind::AVG) {
1279  aggregation_trees_lv = cgen_state_->llInt(reinterpret_cast<int64_t>(
1280  window_func_context->getDerivedAggregationTreesForIntegerTypeWindowExpr()));
1281  } else {
1282  aggregation_trees_lv = cgen_state_->llInt(reinterpret_cast<int64_t>(
1283  window_func_context->getAggregationTreesForIntegerTypeWindowExpr()));
1284  }
1285  }
1286 
1287  CHECK(aggregation_trees_lv);
1288  CHECK(invalid_val_lv);
1289  aggregation_tree_search_func_name += "_aggregation_tree";
1290  aggregation_tree_getter_func_name += "_aggregation_tree";
1291 
1292  // get the aggregate tree of the current partition from a window context
1293  auto aggregation_trees_ptr = CodegenUtil::createPtrWithHoistedMemoryAddr(
1294  cgen_state_.get(),
1295  &code_generator,
1296  co,
1297  aggregation_trees_lv,
1298  ppi64_type,
1300  .front();
1301  auto target_aggregation_tree_lv = cgen_state_->emitCall(
1302  aggregation_tree_getter_func_name, {aggregation_trees_ptr, partition_index_lv});
1303 
1304  // a depth of segment tree
1305  const auto tree_depth_buf = cgen_state_->llInt(
1306  reinterpret_cast<int64_t>(window_func_context->getAggregateTreeDepth()));
1307  const auto tree_depth_buf_ptr = CodegenUtil::createPtrWithHoistedMemoryAddr(
1308  cgen_state_.get(),
1309  &code_generator,
1310  co,
1311  tree_depth_buf,
1312  pi64_type,
1314  .front();
1315  const auto current_partition_tree_depth_buf_ptr = cgen_state_->ir_builder_.CreateGEP(
1316  get_int_type(64, cgen_state_->context_), tree_depth_buf_ptr, partition_index_lv);
1317  const auto current_partition_tree_depth_lv = cgen_state_->ir_builder_.CreateLoad(
1318  current_partition_tree_depth_buf_ptr->getType()->getPointerElementType(),
1319  current_partition_tree_depth_buf_ptr);
1320 
1321  // a fanout of the current partition's segment tree
1322  const auto aggregation_tree_fanout_lv = cgen_state_->llInt(
1323  static_cast<int64_t>(window_func_context->getAggregateTreeFanout()));
1324 
1325  // agg_type
1326  const auto agg_type_lv =
1327  cgen_state_->llInt(static_cast<int32_t>(window_func->getKind()));
1328 
1329  // send a query to the aggregate tree with the frame range:
1330  // `frame_start_bound_lv` ~ `frame_end_bound_lv`
1331  auto res_lv =
1332  cgen_state_->emitCall(aggregation_tree_search_func_name,
1333  {target_aggregation_tree_lv,
1334  frame_start_bound_lv,
1335  frame_end_bound_lv,
1336  current_partition_tree_depth_lv,
1337  aggregation_tree_fanout_lv,
1338  cgen_state_->llBool(agg_expr_ti.is_decimal()),
1339  cgen_state_->llInt((int64_t)agg_expr_ti.get_scale()),
1340  invalid_val_lv,
1341  null_val_lv,
1342  agg_type_lv});
1343 
1344  // handling returned null value if exists
1345  std::string null_handler_func_name{"handle_null_val_"};
1346  std::vector<llvm::Value*> null_handler_args{res_lv, null_val_lv};
1347 
1348  // determine null_handling function's name
1349  if (window_func->getKind() == SqlWindowFunctionKind::AVG) {
1350  // average aggregate function returns a value as a double
1351  // (and our search* function also returns a double)
1352  if (agg_expr_ti.is_fp()) {
1353  // fp type: double null value
1354  null_handler_func_name += "double_double";
1355  } else {
1356  // non-fp type: int64_t null type
1357  null_handler_func_name += "double_int64_t";
1358  }
1359  } else if (agg_expr_ti.is_fp()) {
1360  // fp type: double null value
1361  null_handler_func_name += "double_double";
1362  } else {
1363  // non-fp type: int64_t null type
1364  null_handler_func_name += "int64_t_int64_t";
1365  }
1366  null_handler_func_name += "_window_framing_agg";
1367 
1368  // prepare null_val
1369  if (window_func->getKind() == SqlWindowFunctionKind::COUNT) {
1370  if (agg_expr_ti.is_fp()) {
1371  null_handler_args.push_back(cgen_state_->llFp((double)0));
1372  } else {
1373  null_handler_args.push_back(cgen_state_->llInt((int64_t)0));
1374  }
1375  } else if (window_func->getKind() == SqlWindowFunctionKind::AVG) {
1376  null_handler_args.push_back(cgen_state_->inlineFpNull(SQLTypeInfo(kDOUBLE)));
1377  } else {
1378  null_handler_args.push_back(cgen_state_->castToTypeIn(window_func_null_val, 64));
1379  }
1380  res_lv = cgen_state_->emitCall(null_handler_func_name, null_handler_args);
1381 
1382  // when AGG_TYPE is double, we get a double type return value we expect an integer
1383  // type value for the count aggregation
1384  if (window_func->getKind() == SqlWindowFunctionKind::COUNT && agg_expr_ti.is_fp()) {
1385  return cgen_state_->ir_builder_.CreateFPToSI(
1386  res_lv, get_int_type(64, cgen_state_->context_));
1387  } else if (window_func->getKind() != SqlWindowFunctionKind::COUNT &&
1388  agg_expr_ti.is_date_in_days()) {
1389  // we need to decode the "encoded" date column value
1390  auto date_null_val = get_null_value_by_size(cgen_state_.get(), agg_expr_ti);
1391  if (date_null_val->getType()->getScalarSizeInBits() != 32) {
1392  date_null_val = cgen_state_->castToTypeIn(date_null_val, 32);
1393  }
1394  return cgen_state_->emitCall("fixed_width_date_decode",
1395  {res_lv, date_null_val, null_val_lv});
1396  }
1397  return res_lv;
1398  } else {
1399  auto agg_name = get_window_agg_name(window_func->getKind(), window_func_ti);
1400  Analyzer::Expr* arg_target_expr;
1401  std::vector<llvm::Value*> agg_func_args{aggregate_state};
1402  auto modified_window_func_null_val = window_func_null_val;
1403  if (args.empty() ||
1404  (window_func->getKind() == SqlWindowFunctionKind::COUNT &&
1405  dynamic_cast<Analyzer::Constant*>(args.front().get()) != nullptr)) {
1406  // a count aggregation without an expression: COUNT(1) or COUNT(*)
1407  agg_func_args.push_back(cgen_state_->llInt(int64_t(1)));
1408  } else {
1409  // we use #base_agg_func_name##_skip_val agg function
1410  // i.e.,int64_t agg_sum_skip_val(int64_t* agg, int64_t val, int64_t skip_val)
1411  arg_target_expr = args.front().get();
1412  const auto arg_lvs = code_generator.codegen(arg_target_expr, true, co);
1413  CHECK_EQ(arg_lvs.size(), size_t(1));
1414  // handling current row's value
1415  auto crt_val = arg_lvs.front();
1416  if ((window_func->getKind() == SqlWindowFunctionKind::SUM ||
1417  window_func->getKind() == SqlWindowFunctionKind::SUM_IF) &&
1418  !window_func_ti.is_fp()) {
1419  crt_val = code_generator.codegenCastBetweenIntTypes(
1420  arg_lvs.front(), args.front()->get_type_info(), window_func_ti, false);
1421  }
1422  agg_func_args.push_back(window_func_ti.get_type() == kFLOAT
1423  ? crt_val
1424  : cgen_state_->castToTypeIn(crt_val, 64));
1425  // handle null value and conditional value for conditional aggregates if necessary
1426  llvm::Value* cond_lv{nullptr};
1427  if (window_function_conditional_aggregate(window_func->getKind())) {
1428  switch (window_func->getKind()) {
1430  // COUNT_IF has a single condition expr which is always bool type
1431  modified_window_func_null_val = cgen_state_->castToTypeIn(
1432  cgen_state_->inlineNull(SQLTypeInfo(kTINYINT)), 64);
1433  break;
1435  // FP type input col uses its own null value depending on the type
1436  // otherwise (integer type input col), we use 8-byte type
1437  if (args.front()->get_type_info().is_integer()) {
1438  agg_func_args[1] = cgen_state_->castToTypeIn(agg_func_args[1], 64);
1439  // keep the null value but casting its type to 8-byte
1440  modified_window_func_null_val =
1441  cgen_state_->castToTypeIn(window_func_null_val, 64);
1442  }
1443  auto cond_expr_lv = code_generator.codegen(args[1].get(), true, co).front();
1444  cond_lv =
1445  codegenConditionalAggregateCondValSelector(cond_expr_lv, kSUM_IF, co);
1446  }
1447  default:
1448  break;
1449  }
1450  }
1451  agg_name += "_skip_val";
1452  agg_func_args.push_back(modified_window_func_null_val);
1453  if (cond_lv) {
1454  agg_func_args.push_back(cond_lv);
1455  }
1456  }
1457  cgen_state_->emitCall(agg_name, agg_func_args);
1458  if (window_func->getKind() == SqlWindowFunctionKind::AVG) {
1459  codegenWindowAvgEpilogue(
1460  &code_generator, co, agg_func_args[1], window_func_null_val);
1461  }
1462  return codegenAggregateWindowState(&code_generator, co, aggregate_state);
1463  }
1464 }
1465 
1467  const CompilationOptions& co,
1468  llvm::Value* crt_val,
1469  llvm::Value* window_func_null_val) {
1470  AUTOMATIC_IR_METADATA(cgen_state_.get());
1471  const auto window_func_context =
1473  const auto window_func = window_func_context->getWindowFunction();
1474  const auto window_func_ti = get_adjusted_window_type_info(window_func);
1475  const auto pi32_type =
1476  llvm::PointerType::get(get_int_type(32, cgen_state_->context_), 0);
1477  const auto pi64_type =
1478  llvm::PointerType::get(get_int_type(64, cgen_state_->context_), 0);
1479  const auto aggregate_state_type =
1480  window_func_ti.get_type() == kFLOAT ? pi32_type : pi64_type;
1481  const auto aggregate_state_count_i64 = cgen_state_->llInt(
1482  reinterpret_cast<const int64_t>(window_func_context->aggregateStateCount()));
1483  auto aggregate_state_count = CodegenUtil::createPtrWithHoistedMemoryAddr(
1484  cgen_state_.get(),
1485  code_generator,
1486  co,
1487  aggregate_state_count_i64,
1488  aggregate_state_type,
1490  .front();
1491  std::string agg_count_func_name = "agg_count";
1492  switch (window_func_ti.get_type()) {
1493  case kFLOAT: {
1494  agg_count_func_name += "_float";
1495  break;
1496  }
1497  case kDOUBLE: {
1498  agg_count_func_name += "_double";
1499  break;
1500  }
1501  default: {
1502  break;
1503  }
1504  }
1505  agg_count_func_name += "_skip_val";
1506  cgen_state_->emitCall(agg_count_func_name,
1507  {aggregate_state_count, crt_val, window_func_null_val});
1508 }
1509 
1511  const CompilationOptions& co,
1512  llvm::Value* aggregate_state) {
1513  AUTOMATIC_IR_METADATA(cgen_state_.get());
1514  const auto pi32_type =
1515  llvm::PointerType::get(get_int_type(32, cgen_state_->context_), 0);
1516  const auto pi64_type =
1517  llvm::PointerType::get(get_int_type(64, cgen_state_->context_), 0);
1518  const auto window_func_context =
1520  const Analyzer::WindowFunction* window_func = window_func_context->getWindowFunction();
1521  const auto window_func_ti = get_adjusted_window_type_info(window_func);
1522  const auto aggregate_state_type =
1523  window_func_ti.get_type() == kFLOAT ? pi32_type : pi64_type;
1524  if (window_func->getKind() == SqlWindowFunctionKind::AVG) {
1525  const auto aggregate_state_count_i64 = cgen_state_->llInt(
1526  reinterpret_cast<const int64_t>(window_func_context->aggregateStateCount()));
1527  auto aggregate_state_count = CodegenUtil::createPtrWithHoistedMemoryAddr(
1528  cgen_state_.get(),
1529  code_generator,
1530  co,
1531  aggregate_state_count_i64,
1532  aggregate_state_type,
1534  .front();
1535  const auto double_null_lv = cgen_state_->inlineFpNull(SQLTypeInfo(kDOUBLE));
1536  switch (window_func_ti.get_type()) {
1537  case kFLOAT: {
1538  return cgen_state_->emitCall(
1539  "load_avg_float", {aggregate_state, aggregate_state_count, double_null_lv});
1540  }
1541  case kDOUBLE: {
1542  return cgen_state_->emitCall(
1543  "load_avg_double", {aggregate_state, aggregate_state_count, double_null_lv});
1544  }
1545  case kDECIMAL: {
1546  return cgen_state_->emitCall(
1547  "load_avg_decimal",
1548  {aggregate_state,
1549  aggregate_state_count,
1550  double_null_lv,
1551  cgen_state_->llInt<int32_t>(window_func_ti.get_scale())});
1552  }
1553  default: {
1554  return cgen_state_->emitCall(
1555  "load_avg_int", {aggregate_state, aggregate_state_count, double_null_lv});
1556  }
1557  }
1558  }
1559  if (window_func->getKind() == SqlWindowFunctionKind::COUNT) {
1560  return cgen_state_->ir_builder_.CreateLoad(
1561  aggregate_state->getType()->getPointerElementType(), aggregate_state);
1562  }
1563  switch (window_func_ti.get_type()) {
1564  case kFLOAT: {
1565  return cgen_state_->emitCall("load_float", {aggregate_state});
1566  }
1567  case kDOUBLE: {
1568  return cgen_state_->emitCall("load_double", {aggregate_state});
1569  }
1570  default: {
1571  return cgen_state_->ir_builder_.CreateLoad(
1572  aggregate_state->getType()->getPointerElementType(), aggregate_state);
1573  }
1574  }
1575 }
1576 
1578  llvm::Value* cond_lv,
1579  SQLAgg const aggKind,
1580  CompilationOptions const& co) const {
1581  llvm::Value* res_cond_lv{nullptr};
1582  switch (aggKind) {
1583  case kSUM_IF:
1584  if (cond_lv->getType()->isIntegerTy(1)) {
1585  // cond_expr returns i1 type val, just need to cast to i8 type
1586  // i.e., cond_expr IS NULL
1587  res_cond_lv = cgen_state_->castToTypeIn(cond_lv, 8);
1588  } else {
1589  CHECK(cond_lv->getType()->isIntegerTy(8));
1590  // cond_expr may have null value instead of upcasted bool (i1-type) value
1591  // so we have to correctly set true condition
1592  // i.e., i8 @gt_int32_t_nullable_lhs(..., i64 -2147483648, i8 -128)
1593  // has one of the following i8-type values: 1, 0, -128
1594  auto true_cond_lv =
1595  cgen_state_->ir_builder_.CreateICmpEQ(cond_lv, cgen_state_->llInt((int8_t)1));
1596  res_cond_lv = cgen_state_->ir_builder_.CreateSelect(
1597  true_cond_lv, cgen_state_->llInt((int8_t)1), cgen_state_->llInt((int8_t)0));
1598  }
1599  break;
1600  default:
1601  break;
1602  }
1603  return res_cond_lv;
1604 }
std::string get_col_type_name_by_size(const size_t size, const bool is_fp)
static constexpr int64_t kSecsPerDay
bool hasRangeModeFraming() const
Definition: Analyzer.h:2959
SqlWindowFrameBoundType
Definition: sqldefs.h:202
bool isCurrentRowBound() const
Definition: Analyzer.h:2841
SQLAgg
Definition: sqldefs.h:76
#define CHECK_EQ(x, y)
Definition: Logger.h:301
llvm::Value * castToTypeIn(llvm::Value *val, const size_t bit_width)
Definition: CgenState.cpp:150
SqlWindowFunctionKind getKind() const
Definition: Analyzer.h:2925
llvm::Value * num_elem_current_partition_lv
HOST DEVICE int get_size() const
Definition: sqltypes.h:403
bool hasTimestampTypeFrameBound() const
Definition: Analyzer.h:2833
llvm::Value * current_col_value_lv
bool isFrameNavigateWindowFunction() const
Definition: Analyzer.h:2979
void codegenWindowFunctionStateInit(CodeGenerator *code_generator, const CompilationOptions &co, llvm::Value *aggregate_state)
Definition: sqltypes.h:76
int64_t * getNullValueEndPos() const
bool window_function_conditional_aggregate(const SqlWindowFunctionKind kind)
Definition: WindowContext.h:78
llvm::Value * current_partition_start_offset_lv
#define LOG(tag)
Definition: Logger.h:285
llvm::Value * current_row_pos_lv
llvm::Value * target_partition_rowid_ptr_lv
bool is_fp() const
Definition: sqltypes.h:573
llvm::Value * codegenFrameBound(bool for_start_bound, bool for_range_mode, bool for_window_frame_naviation, const Analyzer::WindowFrame *frame_bound, bool is_timestamp_type_frame, llvm::Value *order_key_null_val, const WindowFrameBoundFuncArgs &args)
llvm::Value * frame_end_bound_expr_lv
llvm::Value * num_elem_current_partition_lv
llvm::Value * nulls_first_lv
const std::vector< SQLTypeInfo > & getOrderKeyColumnBufferTypes() const
llvm::Value * posArg(const Analyzer::Expr *) const
Definition: ColumnIR.cpp:590
#define UNREACHABLE()
Definition: Logger.h:338
llvm::Value * aggregateWindowStatePtr(CodeGenerator *code_generator, const CompilationOptions &co)
size_t elementCount() const
llvm::Type * get_fp_type(const int width, llvm::LLVMContext &context)
std::string getFramingFuncName(const std::string &bound_type, const std::string &order_col_type, const std::string &op_type, bool for_timestamp_type) const
const int32_t * counts() const
const Analyzer::WindowFrame * getFrameStartBound() const
Definition: Analyzer.h:2937
HOST DEVICE SQLTypes get_type() const
Definition: sqltypes.h:391
llvm::Value * target_partition_sorted_rowid_ptr_lv
const Analyzer::WindowFrame * getFrameEndBound() const
Definition: Analyzer.h:2944
llvm::Value * target_partition_rowid_ptr_lv
llvm::Type * get_int_type(const int width, llvm::LLVMContext &context)
const std::vector< std::shared_ptr< Analyzer::Expr > > & getOrderKeys() const
Definition: Analyzer.h:2933
static WindowFunctionContext * getActiveWindowFunctionContext(Executor *executor)
std::string get_window_agg_name(const SqlWindowFunctionKind kind, const SQLTypeInfo &window_func_ti)
int64_t * getNullValueStartPos() const
const int64_t * partitionStartOffset() const
std::pair< llvm::Value *, llvm::Value * > codegenFrameNullRange(WindowFunctionContext *window_func_context, CodeGenerator *code_generator, const CompilationOptions &co, llvm::Value *partition_index_lv) const
size_t partitionCount() const
SqlWindowFrameBoundType getBoundType() const
Definition: Analyzer.h:2826
llvm::Value * codegenWindowPosition(const WindowFunctionContext *window_func_context, llvm::Value *pos_arg)
Definition: ColumnIR.cpp:235
llvm::Value * null_start_pos_lv
static const WindowProjectNodeContext * get(Executor *executor)
const std::vector< std::shared_ptr< Analyzer::Expr > > & getArgs() const
Definition: Analyzer.h:2927
int get_logical_size() const
Definition: sqltypes.h:421
std::vector< llvm::Value * > prepareRangeModeFuncArgs(bool for_start_bound, const Analyzer::WindowFrame *frame_bound, bool is_timestamp_type_frame, llvm::Value *order_key_null_val, const WindowFrameBoundFuncArgs &frame_args) const
const SQLTypeInfo getFirstOrderColTypeInfo(WindowFunctionContext *window_func_context) const
const WindowFunctionContext * activateWindowFunctionContext(Executor *executor, const size_t target_index) const
std::pair< llvm::Value *, llvm::Value * > codegenWindowFrameBounds(WindowFunctionContext *window_func_context, const Analyzer::WindowFrame *frame_start_bound, const Analyzer::WindowFrame *frame_end_bound, llvm::Value *order_key_col_null_val_lv, WindowFrameBoundFuncArgs &args, CodeGenerator &code_generator)
llvm::Value * codegenCastBetweenIntTypes(llvm::Value *operand_lv, const SQLTypeInfo &operand_ti, const SQLTypeInfo &ti, bool upscale=true)
Definition: CastIR.cpp:427
const Analyzer::Expr * getBoundExpr() const
Definition: Analyzer.h:2828
llvm::ConstantFP * llFp(const float v) const
Definition: CgenState.h:253
std::pair< llvm::BasicBlock *, llvm::Value * > codegenWindowResetStateControlFlow(CodeGenerator *code_generator, const CompilationOptions &co)
#define AUTOMATIC_IR_METADATA(CGENSTATE)
const SQLTypeInfo & get_type_info() const
Definition: Analyzer.h:79
static const int NUM_EXECUTION_DEVICES
std::vector< llvm::Value * > codegen(const Analyzer::Expr *, const bool fetch_columns, const CompilationOptions &)
Definition: IRCodegen.cpp:30
llvm::Value * current_partition_start_offset_lv
Definition: sqltypes.h:80
llvm::Value * codegenLoadCurrentValueFromColBuf(WindowFunctionContext *window_func_context, CodeGenerator &code_generator, WindowFrameBoundFuncArgs &args) const
HOST DEVICE EncodingType get_compression() const
Definition: sqltypes.h:399
llvm::Value * target_partition_sorted_rowid_ptr_lv
void codegenWindowAvgEpilogue(CodeGenerator *code_generator, const CompilationOptions &co, llvm::Value *crt_val, llvm::Value *window_func_null_val)
const std::string getOrderKeyTypeName(WindowFunctionContext *window_func_context) const
llvm::Value * codegenConditionalAggregateCondValSelector(llvm::Value *cond_lv, SQLAgg const aggKind, CompilationOptions const &co) const
constexpr float inline_fp_null_value< float >()
std::pair< llvm::Value *, llvm::Value * > codegenFrameBoundRange(const Analyzer::WindowFunction *window_func, CodeGenerator &code_generator, const CompilationOptions &co)
const std::vector< const int8_t * > & getOrderKeyColumnBuffers() const
constexpr double inline_fp_null_value< double >()
llvm::Value * null_end_pos_lv
const int64_t * partitionNumCountBuf() const
llvm::Value * codegenWindowFunctionAggregate(CodeGenerator *code_generator, const CompilationOptions &co)
llvm::Value * toBool(llvm::Value *)
Definition: LogicalIR.cpp:344
llvm::Value * codegenCurrentPartitionIndex(const WindowFunctionContext *window_func_context, CodeGenerator *code_generator, const CompilationOptions &co, llvm::Value *current_row_pos_lv)
SqlWindowFunctionKind
Definition: sqldefs.h:129
HOST DEVICE int get_comp_param() const
Definition: sqltypes.h:402
llvm::Value * codegenWindowNavigationFunctionOnFrame(const CompilationOptions &co)
llvm::Value * codegenFrameBoundExpr(const Analyzer::WindowFunction *window_func, const Analyzer::WindowFrame *frame_bound, CodeGenerator &code_generator, const CompilationOptions &co)
llvm::ConstantInt * llInt(const T v) const
Definition: CgenState.h:249
llvm::Value * order_key_buf_ptr_lv
#define CHECK(condition)
Definition: Logger.h:291
llvm::Value * int64_t_zero_val_lv
const int64_t * sortedPartition() const
WindowPartitionBufferPtrs codegenLoadPartitionBuffers(WindowFunctionContext *window_func_context, CodeGenerator *code_generator, const CompilationOptions &co, llvm::Value *partition_index_lv) const
int64_t inline_int_null_val(const SQL_TYPE_INFO &ti)
int64_t inline_fixed_encoding_null_val(const SQL_TYPE_INFO &ti)
bool g_cluster
std::pair< std::string, llvm::Value * > codegenLoadOrderKeyBufPtr(WindowFunctionContext *window_func_context, CodeGenerator *code_generator, const CompilationOptions &co) const
const Analyzer::WindowFunction * getWindowFunction() const
bool is_dict_encoded_string() const
Definition: sqltypes.h:643
Definition: sqltypes.h:72
const int32_t * payload() const
llvm::Value * get_null_value_by_size(CgenState *cgen_state, SQLTypeInfo col_ti)
std::vector< llvm::Value * > createPtrWithHoistedMemoryAddr(CgenState *cgen_state, CodeGenerator *code_generator, CompilationOptions const &co, llvm::ConstantInt *ptr_int_val, llvm::Type *type, size_t num_devices_to_hoist_literal)
size_t getOrderKeySize(WindowFunctionContext *window_func_context) const
llvm::Value * codegenAggregateWindowState(CodeGenerator *code_generator, const CompilationOptions &co, llvm::Value *aggregate_state)
llvm::Value * int64_t_one_val_lv
llvm::Value * codegenWindowFunctionAggregateCalls(llvm::Value *aggregate_state, const CompilationOptions &co)
llvm::Value * frame_start_bound_expr_lv
llvm::Value * codegenWindowFunction(const size_t target_index, const CompilationOptions &co)
bool is_date() const
Definition: sqltypes.h:1028
std::string order_type_col_name
llvm::Value * get_null_value_by_size_with_encoding(CgenState *cgen_state, SQLTypeInfo col_ti)
std::vector< llvm::Value * > prepareRowModeFuncArgs(bool for_start_bound, SqlWindowFrameBoundType bound_type, const WindowFrameBoundFuncArgs &args) const
SQLTypeInfo get_adjusted_window_type_info(const Analyzer::WindowFunction *window_func)