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