OmniSciDB  c0231cc57d
 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 "Execute.h"
19 #include "WindowContext.h"
20 
21 llvm::Value* Executor::codegenWindowFunction(const size_t target_index,
22  const CompilationOptions& co) {
23  AUTOMATIC_IR_METADATA(cgen_state_.get());
24  CodeGenerator code_generator(this);
25 
26  const auto window_func_context =
28  target_index);
29  const auto window_func = window_func_context->getWindowFunction();
30  switch (window_func->getKind()) {
35  // they are always evaluated on the entire partition
36  return code_generator.codegenWindowPosition(window_func_context,
37  code_generator.posArg(nullptr));
38  }
41  // they are always evaluated on the entire partition
42  return cgen_state_->emitCall("percent_window_func",
43  {cgen_state_->llInt(reinterpret_cast<const int64_t>(
44  window_func_context->output())),
45  code_generator.posArg(nullptr)});
46  }
51  // they are always evaluated on the current frame
53  const auto& args = window_func->getArgs();
54  CHECK(!args.empty());
55  const auto arg_lvs = code_generator.codegen(args.front().get(), true, co);
56  CHECK_EQ(arg_lvs.size(), size_t(1));
57  return arg_lvs.front();
58  }
64  // they are always evaluated on the current frame
65  return codegenWindowFunctionAggregate(co);
66  }
69  return codegenWindowFunctionOnFrame(co);
70  }
71  default: {
72  LOG(FATAL) << "Invalid window function kind";
73  }
74  }
75  return nullptr;
76 }
77 
78 namespace {
79 
81  const SQLTypeInfo& window_func_ti) {
82  std::string agg_name;
83  switch (kind) {
85  agg_name = "agg_min";
86  break;
87  }
89  agg_name = "agg_max";
90  break;
91  }
94  agg_name = "agg_sum";
95  break;
96  }
98  agg_name = "agg_count";
99  break;
100  }
101  default: {
102  LOG(FATAL) << "Invalid window function kind";
103  }
104  }
105  switch (window_func_ti.get_type()) {
106  case kFLOAT: {
107  agg_name += "_float";
108  break;
109  }
110  case kDOUBLE: {
111  agg_name += "_double";
112  break;
113  }
114  default: {
115  break;
116  }
117  }
118  return agg_name;
119 }
120 
122  const auto& args = window_func->getArgs();
123  return ((window_func->getKind() == SqlWindowFunctionKind::COUNT && !args.empty()) ||
124  window_func->getKind() == SqlWindowFunctionKind::AVG)
125  ? args.front()->get_type_info()
126  : window_func->get_type_info();
127 }
128 
129 std::string get_col_type_name_by_size(const size_t size, const bool is_fp) {
130  if (is_fp) {
131  if (size == 4) {
132  return "float";
133  }
134  return "double";
135  }
136  if (size == 1) {
137  return "int8_t";
138  } else if (size == 2) {
139  return "int16_t";
140  } else if (size == 4) {
141  return "int32_t";
142  }
143  return "int64_t";
144 }
145 
146 llvm::Value* get_null_value_by_size(CgenState* cgen_state, SQLTypeInfo col_ti) {
147  if (col_ti.is_fp()) {
148  if (col_ti.get_type() == kFLOAT) {
149  return cgen_state->llFp(inline_fp_null_value<float>());
150  } else {
151  return cgen_state->llFp(inline_fp_null_value<double>());
152  }
153  } else if (col_ti.is_dict_encoded_string()) {
154  if (col_ti.get_size() == 2) {
155  return cgen_state->llInt((int16_t)inline_int_null_value<int16_t>());
156  } else {
157  CHECK_EQ(col_ti.get_size(), 4);
158  return cgen_state->llInt((int32_t)inline_int_null_value<int32_t>());
159  }
160  } else {
161  switch (col_ti.get_type()) {
162  case kBOOLEAN:
163  case kTINYINT:
164  return cgen_state->llInt((int8_t)inline_int_null_value<int8_t>());
165  case kSMALLINT:
166  return cgen_state->llInt((int16_t)inline_int_null_value<int16_t>());
167  case kINT:
168  return cgen_state->llInt((int32_t)inline_int_null_value<int32_t>());
169  case kBIGINT:
170  case kTIMESTAMP:
171  case kTIME:
172  case kDATE:
173  case kINTERVAL_DAY_TIME:
175  case kDECIMAL:
176  case kNUMERIC:
177  return cgen_state->llInt((int64_t)inline_int_null_value<int64_t>());
178  default:
179  abort();
180  }
181  return cgen_state->llInt(inline_int_null_val(col_ti));
182  }
183 }
184 
186  SQLTypeInfo col_ti) {
187  if (col_ti.is_fp()) {
188  if (col_ti.get_type() == kFLOAT) {
189  return cgen_state->llFp(inline_fp_null_value<float>());
190  } else {
191  return cgen_state->llFp(inline_fp_null_value<double>());
192  }
193  } else {
194  llvm::Value* ret_val{nullptr};
195  if (col_ti.get_compression() == kENCODING_FIXED ||
197  ret_val = cgen_state->llInt(inline_fixed_encoding_null_val(col_ti));
198  } else {
199  ret_val = cgen_state->llInt(inline_int_null_val(col_ti));
200  }
201  size_t ret_val_col_size_in_bytes = col_ti.get_logical_size() * 8;
202  if (ret_val->getType()->getIntegerBitWidth() > ret_val_col_size_in_bytes) {
203  return cgen_state->castToTypeIn(ret_val, ret_val_col_size_in_bytes);
204  }
205  return ret_val;
206  }
207 }
208 
209 } // namespace
210 
212  AUTOMATIC_IR_METADATA(cgen_state_.get());
213  const auto window_func_context =
215  const auto window_func = window_func_context->getWindowFunction();
216  const auto arg_ti = get_adjusted_window_type_info(window_func);
217  llvm::Type* aggregate_state_type =
218  arg_ti.get_type() == kFLOAT
219  ? llvm::PointerType::get(get_int_type(32, cgen_state_->context_), 0)
220  : llvm::PointerType::get(get_int_type(64, cgen_state_->context_), 0);
221  const auto aggregate_state_i64 = cgen_state_->llInt(
222  reinterpret_cast<const int64_t>(window_func_context->aggregateState()));
223  return cgen_state_->ir_builder_.CreateIntToPtr(aggregate_state_i64,
224  aggregate_state_type);
225 }
226 
228  AUTOMATIC_IR_METADATA(cgen_state_.get());
229  const auto reset_state_false_bb = codegenWindowResetStateControlFlow();
230  auto aggregate_state = aggregateWindowStatePtr();
231  llvm::Value* aggregate_state_count = nullptr;
232  const auto window_func_context =
234  const auto window_func = window_func_context->getWindowFunction();
235  if (window_func->getKind() == SqlWindowFunctionKind::AVG) {
236  const auto aggregate_state_count_i64 = cgen_state_->llInt(
237  reinterpret_cast<const int64_t>(window_func_context->aggregateStateCount()));
238  const auto pi64_type =
239  llvm::PointerType::get(get_int_type(64, cgen_state_->context_), 0);
240  aggregate_state_count =
241  cgen_state_->ir_builder_.CreateIntToPtr(aggregate_state_count_i64, pi64_type);
242  }
243  codegenWindowFunctionStateInit(aggregate_state);
244  if (window_func->getKind() == SqlWindowFunctionKind::AVG) {
245  const auto count_zero = cgen_state_->llInt(int64_t(0));
246  cgen_state_->emitCall("agg_id", {aggregate_state_count, count_zero});
247  }
248  cgen_state_->ir_builder_.CreateBr(reset_state_false_bb);
249  cgen_state_->ir_builder_.SetInsertPoint(reset_state_false_bb);
251  return codegenWindowFunctionAggregateCalls(aggregate_state, co);
252 }
253 
255  AUTOMATIC_IR_METADATA(cgen_state_.get());
256  const auto window_func_context =
258  const auto bitset = cgen_state_->llInt(
259  reinterpret_cast<const int64_t>(window_func_context->partitionStart()));
260  const auto min_val = cgen_state_->llInt(int64_t(0));
261  const auto max_val = cgen_state_->llInt(window_func_context->elementCount() - 1);
262  const auto null_val = cgen_state_->llInt(inline_int_null_value<int64_t>());
263  const auto null_bool_val = cgen_state_->llInt<int8_t>(inline_int_null_value<int8_t>());
264  CodeGenerator code_generator(this);
265  const auto reset_state =
266  code_generator.toBool(cgen_state_->emitCall("bit_is_set",
267  {bitset,
268  code_generator.posArg(nullptr),
269  min_val,
270  max_val,
271  null_val,
272  null_bool_val}));
273  const auto reset_state_true_bb = llvm::BasicBlock::Create(
274  cgen_state_->context_, "reset_state.true", cgen_state_->current_func_);
275  const auto reset_state_false_bb = llvm::BasicBlock::Create(
276  cgen_state_->context_, "reset_state.false", cgen_state_->current_func_);
277  cgen_state_->ir_builder_.CreateCondBr(
278  reset_state, reset_state_true_bb, reset_state_false_bb);
279  cgen_state_->ir_builder_.SetInsertPoint(reset_state_true_bb);
280  return reset_state_false_bb;
281 }
282 
283 void Executor::codegenWindowFunctionStateInit(llvm::Value* aggregate_state) {
284  AUTOMATIC_IR_METADATA(cgen_state_.get());
285  const auto window_func_context =
287  const auto window_func = window_func_context->getWindowFunction();
288  const auto window_func_ti = get_adjusted_window_type_info(window_func);
289  const auto window_func_null_val =
290  window_func_ti.is_fp()
291  ? cgen_state_->inlineFpNull(window_func_ti)
292  : cgen_state_->castToTypeIn(cgen_state_->inlineIntNull(window_func_ti), 64);
293  llvm::Value* window_func_init_val;
294  if (window_func_context->getWindowFunction()->getKind() ==
296  switch (window_func_ti.get_type()) {
297  case kFLOAT: {
298  window_func_init_val = cgen_state_->llFp(float(0));
299  break;
300  }
301  case kDOUBLE: {
302  window_func_init_val = cgen_state_->llFp(double(0));
303  break;
304  }
305  default: {
306  window_func_init_val = cgen_state_->llInt(int64_t(0));
307  break;
308  }
309  }
310  } else {
311  window_func_init_val = window_func_null_val;
312  }
313  const auto pi32_type =
314  llvm::PointerType::get(get_int_type(32, cgen_state_->context_), 0);
315  switch (window_func_ti.get_type()) {
316  case kDOUBLE: {
317  cgen_state_->emitCall("agg_id_double", {aggregate_state, window_func_init_val});
318  break;
319  }
320  case kFLOAT: {
321  aggregate_state =
322  cgen_state_->ir_builder_.CreateBitCast(aggregate_state, pi32_type);
323  cgen_state_->emitCall("agg_id_float", {aggregate_state, window_func_init_val});
324  break;
325  }
326  default: {
327  cgen_state_->emitCall("agg_id", {aggregate_state, window_func_init_val});
328  break;
329  }
330  }
331 }
332 
334  AUTOMATIC_IR_METADATA(cgen_state_.get());
335  const auto window_func_context =
337  const auto window_func = window_func_context->getWindowFunction();
338  const auto window_func_kind = window_func->getKind();
339  const auto& args = window_func->getArgs();
340  CHECK(args.size() >= 1 && args.size() <= 3);
341  CodeGenerator code_generator(this);
342  const auto offset_lv =
343  cgen_state_->castToTypeIn(code_generator.codegen(args[1].get(), true, co)[0], 64);
344 
345  // codegen frame bound expr if necessary
346  const auto frame_start_bound = window_func->getFrameStartBound();
347  const auto frame_end_bound = window_func->getFrameEndBound();
348  auto frame_start_bound_expr_lv =
349  codegenFrameBoundExpr(window_func, frame_start_bound, code_generator, co);
350  auto frame_end_bound_expr_lv =
351  codegenFrameBoundExpr(window_func, frame_end_bound, code_generator, co);
352  CHECK(frame_start_bound_expr_lv);
353  CHECK(frame_end_bound_expr_lv);
354 
355  auto current_row_pos_lv = code_generator.posArg(nullptr);
356  auto partition_index_lv =
357  codegenCurrentPartitionIndex(window_func_context, current_row_pos_lv);
358 
359  llvm::Value* res_lv{nullptr};
360  // currently, we only support below two window functions on frame
361  // todo (yonnmin): remove this when supporting more window functions on frame
362  CHECK(window_func_kind == SqlWindowFunctionKind::LEAD_IN_FRAME ||
363  window_func_kind == SqlWindowFunctionKind::LAG_IN_FRAME);
364  const auto pi32_type =
365  llvm::PointerType::get(get_int_type(32, cgen_state_->context_), 0);
366  const auto pi64_type =
367  llvm::PointerType::get(get_int_type(64, cgen_state_->context_), 0);
368  bool is_lag_in_frame = window_func_kind == SqlWindowFunctionKind::LAG_IN_FRAME;
369 
370  // ordering column buffer
371  const auto target_col_ti = window_func->getArgs().front()->get_type_info();
372  const auto target_col_size = target_col_ti.get_size();
373  const auto target_col_type_name =
374  get_col_type_name_by_size(target_col_size, target_col_ti.is_fp());
375  const auto target_col_logical_type_name = get_col_type_name_by_size(
376  window_func->get_type_info().get_size(), window_func->get_type_info().is_fp());
377 
378  // when target_column is fixed encoded, we store the actual column value by
379  // considering it, but our resultset analyzer only considers the type without encoding
380  // scheme so we handle them separately
381  auto logical_null_val_lv =
382  get_null_value_by_size(cgen_state_.get(), window_func->get_type_info());
383  auto target_col_null_val_lv =
384  get_null_value_by_size_with_encoding(cgen_state_.get(), target_col_ti);
385  size_t target_col_size_in_byte = target_col_size * 8;
386  llvm::Type* col_buf_ptr_type =
387  target_col_ti.is_fp()
388  ? get_fp_type(target_col_size_in_byte, cgen_state_->context_)
389  : get_int_type(target_col_size_in_byte, cgen_state_->context_);
390  auto col_buf_type = llvm::PointerType::get(col_buf_ptr_type, 0);
391  auto target_col_buf_ptr_lv = cgen_state_->llInt(reinterpret_cast<int64_t>(
392  window_func_context->getColumnBufferForWindowFunctionExpressions().front()));
393  auto target_col_buf_lv =
394  cgen_state_->ir_builder_.CreateIntToPtr(target_col_buf_ptr_lv, col_buf_type);
395 
396  // partial sum of # elems of partitions
397  auto partition_start_offset_buf_lv = cgen_state_->llInt(
398  reinterpret_cast<int64_t>(window_func_context->partitionStartOffset()));
399  auto partition_start_offset_ptr_lv =
400  cgen_state_->ir_builder_.CreateIntToPtr(partition_start_offset_buf_lv, pi64_type);
401 
402  // get start offset of the current partition
403  auto current_partition_start_offset_ptr_lv =
404  cgen_state_->ir_builder_.CreateGEP(get_int_type(64, cgen_state_->context_),
405  partition_start_offset_ptr_lv,
406  partition_index_lv);
407  auto current_partition_start_offset_lv = cgen_state_->ir_builder_.CreateLoad(
408  current_partition_start_offset_ptr_lv->getType()->getPointerElementType(),
409  current_partition_start_offset_ptr_lv);
410 
411  // row_id buf of the current partition
412  const auto partition_rowid_buf_lv =
413  cgen_state_->llInt(reinterpret_cast<int64_t>(window_func_context->payload()));
414  const auto partition_rowid_ptr_lv =
415  cgen_state_->ir_builder_.CreateIntToPtr(partition_rowid_buf_lv, pi32_type);
416  auto target_partition_rowid_ptr_lv =
417  cgen_state_->ir_builder_.CreateGEP(get_int_type(32, cgen_state_->context_),
418  partition_rowid_ptr_lv,
419  current_partition_start_offset_lv);
420 
421  // row_id buf of ordered current partition
422  const auto sorted_rowid_lv = cgen_state_->llInt(
423  reinterpret_cast<int64_t>(window_func_context->sortedPartition()));
424  const auto sorted_rowid_ptr_lv =
425  cgen_state_->ir_builder_.CreateIntToPtr(sorted_rowid_lv, pi64_type);
426  auto target_partition_sorted_rowid_ptr_lv =
427  cgen_state_->ir_builder_.CreateGEP(get_int_type(64, cgen_state_->context_),
428  sorted_rowid_ptr_lv,
429  current_partition_start_offset_lv);
430 
431  // # elems per partition
432  const auto partition_count_buf =
433  cgen_state_->llInt(reinterpret_cast<int64_t>(window_func_context->counts()));
434  auto partition_count_buf_ptr_lv =
435  cgen_state_->ir_builder_.CreateIntToPtr(partition_count_buf, pi32_type);
436 
437  // # elems of the given partition
438  const auto num_elem_current_partition_ptr =
439  cgen_state_->ir_builder_.CreateGEP(get_int_type(32, cgen_state_->context_),
440  partition_count_buf_ptr_lv,
441  partition_index_lv);
442  auto num_elem_current_partition_lv = cgen_state_->castToTypeIn(
443  cgen_state_->ir_builder_.CreateLoad(
444  num_elem_current_partition_ptr->getType()->getPointerElementType(),
445  num_elem_current_partition_ptr),
446  64);
447 
448  const auto order_key_ti = window_func->getOrderKeys().front()->get_type_info();
449  const auto order_key_size = order_key_ti.get_size();
450  const auto order_col_type_name = get_col_type_name_by_size(
451  order_key_size,
452  window_func_context->getOrderKeyColumnBufferTypes().front().is_fp());
453  size_t order_key_size_in_byte = order_key_size * 8;
454 
455  const auto order_key_buf_type = llvm::PointerType::get(
456  get_int_type(order_key_size_in_byte, cgen_state_->context_), 0);
457  const auto order_key_buf = cgen_state_->llInt(
458  reinterpret_cast<int64_t>(window_func_context->getOrderKeyColumnBuffers().front()));
459  auto order_key_buf_ptr_lv =
460  cgen_state_->ir_builder_.CreateIntToPtr(order_key_buf, order_key_buf_type);
461 
462  // null value of the ordering column
463  const auto order_key_buf_ti =
464  window_func_context->getOrderKeyColumnBufferTypes().front();
465  auto order_key_col_null_val_lv =
466  get_null_value_by_size_with_encoding(cgen_state_.get(), order_key_buf_ti);
467 
468  // null range of the aggregate tree
469  const auto null_start_pos_buf = cgen_state_->llInt(
470  reinterpret_cast<int64_t>(window_func_context->getNullValueStartPos()));
471  const auto null_start_pos_buf_ptr =
472  cgen_state_->ir_builder_.CreateIntToPtr(null_start_pos_buf, pi64_type);
473  const auto null_start_pos_ptr =
474  cgen_state_->ir_builder_.CreateGEP(get_int_type(64, cgen_state_->context_),
475  null_start_pos_buf_ptr,
476  partition_index_lv);
477  auto null_start_pos_lv = cgen_state_->ir_builder_.CreateLoad(
478  null_start_pos_ptr->getType()->getPointerElementType(),
479  null_start_pos_ptr,
480  "null_start_pos");
481  const auto null_end_pos_buf = cgen_state_->llInt(
482  reinterpret_cast<int64_t>(window_func_context->getNullValueEndPos()));
483  const auto null_end_pos_buf_ptr =
484  cgen_state_->ir_builder_.CreateIntToPtr(null_end_pos_buf, pi64_type);
485  const auto null_end_pos_ptr = cgen_state_->ir_builder_.CreateGEP(
486  get_int_type(64, cgen_state_->context_), null_end_pos_buf_ptr, partition_index_lv);
487  auto null_end_pos_lv = cgen_state_->ir_builder_.CreateLoad(
488  null_end_pos_ptr->getType()->getPointerElementType(),
489  null_end_pos_ptr,
490  "null_end_pos");
491 
492  std::string compute_row_idx_on_frame_func_name = "compute_";
493  compute_row_idx_on_frame_func_name += order_col_type_name + "_current_row_idx_in_frame";
494  auto cur_row_idx_in_frame_lv =
495  cgen_state_->emitCall(compute_row_idx_on_frame_func_name,
496  {num_elem_current_partition_lv,
497  current_row_pos_lv,
498  order_key_buf_ptr_lv,
499  target_partition_rowid_ptr_lv,
500  target_partition_sorted_rowid_ptr_lv,
501  order_key_col_null_val_lv,
502  null_start_pos_lv,
503  null_end_pos_lv});
504 
505  llvm::Value* frame_start_bound_lv{nullptr};
506  llvm::Value* frame_end_bound_lv{nullptr};
507  std::tie(frame_start_bound_lv, frame_end_bound_lv) =
508  codegenWindowFrameBound(window_func_context,
509  frame_start_bound,
510  frame_end_bound,
511  cur_row_idx_in_frame_lv,
512  cgen_state_->llInt((int64_t)0),
513  order_key_buf_ptr_lv,
514  order_key_col_null_val_lv,
515  frame_start_bound_expr_lv,
516  frame_end_bound_expr_lv,
517  num_elem_current_partition_lv,
518  target_partition_rowid_ptr_lv,
519  target_partition_sorted_rowid_ptr_lv,
520  null_start_pos_lv,
521  null_end_pos_lv,
522  code_generator);
523  CHECK(frame_start_bound_lv);
524  CHECK(frame_end_bound_lv);
525 
526  llvm::Value* modified_cur_row_idx_in_frame_lv{nullptr};
527  if (is_lag_in_frame) {
528  modified_cur_row_idx_in_frame_lv =
529  cgen_state_->ir_builder_.CreateSub(cur_row_idx_in_frame_lv, offset_lv);
530  } else {
531  modified_cur_row_idx_in_frame_lv =
532  cgen_state_->ir_builder_.CreateAdd(cur_row_idx_in_frame_lv, offset_lv);
533  }
534  CHECK(modified_cur_row_idx_in_frame_lv);
535 
536  std::string target_func_name = "get_";
537  target_func_name += target_col_type_name + "_value_";
538  target_func_name += target_col_logical_type_name + "_type_";
539  target_func_name += "in_frame";
540  res_lv = cgen_state_->emitCall(target_func_name,
541  {modified_cur_row_idx_in_frame_lv,
542  frame_start_bound_lv,
543  frame_end_bound_lv,
544  target_col_buf_lv,
545  target_partition_rowid_ptr_lv,
546  target_partition_sorted_rowid_ptr_lv,
547  logical_null_val_lv,
548  target_col_null_val_lv});
549  if (target_col_ti.get_compression() == kENCODING_DATE_IN_DAYS) {
550  res_lv = cgen_state_->emitCall(
551  "encode_date",
552  {res_lv, logical_null_val_lv, cgen_state_->llInt((int64_t)kSecsPerDay)});
553  }
554  CHECK(res_lv);
555  return res_lv;
556 }
557 
559  const Analyzer::WindowFrame* frame_bound,
560  CodeGenerator& code_generator,
561  const CompilationOptions& co) {
562  auto needs_bound_expr_codegen = [](const Analyzer::WindowFrame* window_frame) {
563  return window_frame->getBoundType() == SqlWindowFrameBoundType::EXPR_FOLLOWING ||
564  window_frame->getBoundType() == SqlWindowFrameBoundType::EXPR_PRECEDING;
565  };
566  const auto order_col_ti = window_func->getOrderKeys().front()->get_type_info();
567  auto encode_date_col_val = [&order_col_ti, this](llvm::Value* bound_expr_lv) {
568  if (order_col_ti.get_comp_param() == 16) {
569  return cgen_state_->emitCall(
570  "fixed_width_date_encode_noinline",
571  {bound_expr_lv,
572  cgen_state_->castToTypeIn(cgen_state_->inlineIntNull(SQLTypeInfo(kSMALLINT)),
573  32),
574  cgen_state_->inlineIntNull(SQLTypeInfo(kBIGINT))});
575  } else {
576  return cgen_state_->emitCall("fixed_width_date_encode_noinline",
577  {bound_expr_lv,
578  cgen_state_->inlineIntNull(SQLTypeInfo(kINT)),
579  cgen_state_->inlineIntNull(SQLTypeInfo(kBIGINT))});
580  }
581  };
582  llvm::Value* bound_expr_lv{nullptr};
583  if (needs_bound_expr_codegen(frame_bound)) {
584  auto bound_expr_lvs = code_generator.codegen(frame_bound->getBoundExpr(), true, co);
585  bound_expr_lv = bound_expr_lvs.front();
586  if (order_col_ti.is_date() && window_func->hasRangeModeFraming()) {
587  if (g_cluster) {
588  throw std::runtime_error(
589  "Range mode with date type ordering column is not supported yet.");
590  }
591  bound_expr_lv = encode_date_col_val(bound_expr_lv);
592  }
593  if (frame_bound->getBoundExpr()->get_type_info().get_size() != 8) {
594  bound_expr_lv = cgen_state_->castToTypeIn(bound_expr_lv, 64);
595  }
596  } else {
597  bound_expr_lv = cgen_state_->llInt((int64_t)-1);
598  }
599  CHECK(bound_expr_lv);
600  return bound_expr_lv;
601 }
602 
604  const WindowFunctionContext* window_func_context,
605  llvm::Value* current_row_pos_lv) {
606  const auto pi64_type =
607  llvm::PointerType::get(get_int_type(64, cgen_state_->context_), 0);
608  // given current row's pos, calculate the partition index that it belongs to
609  auto partition_count_lv = cgen_state_->llInt(window_func_context->partitionCount());
610  auto partition_num_count_buf_lv = cgen_state_->llInt(
611  reinterpret_cast<int64_t>(window_func_context->partitionNumCountBuf()));
612  auto partition_num_count_ptr_lv =
613  cgen_state_->ir_builder_.CreateIntToPtr(partition_num_count_buf_lv, pi64_type);
614  return cgen_state_->emitCall(
615  "compute_int64_t_lower_bound",
616  {partition_count_lv, current_row_pos_lv, partition_num_count_ptr_lv});
617 }
618 
619 std::pair<llvm::Value*, llvm::Value*> Executor::codegenWindowFrameBound(
620  WindowFunctionContext* window_func_context,
621  const Analyzer::WindowFrame* frame_start_bound,
622  const Analyzer::WindowFrame* frame_end_bound,
623  llvm::Value* current_row_pos_lv,
624  llvm::Value* current_partition_start_offset_lv,
625  llvm::Value* order_key_buf_ptr_lv,
626  llvm::Value* order_key_col_null_val_lv,
627  llvm::Value* frame_start_bound_expr_lv,
628  llvm::Value* frame_end_bound_expr_lv,
629  llvm::Value* num_elem_current_partition_lv,
630  llvm::Value* target_partition_rowid_ptr_lv,
631  llvm::Value* target_partition_sorted_rowid_ptr_lv,
632  llvm::Value* null_start_pos_lv,
633  llvm::Value* null_end_pos_lv,
634  CodeGenerator& code_generator) {
635  const auto window_func = window_func_context->getWindowFunction();
636  CHECK(window_func);
637  std::string order_col_type_name{""};
638  llvm::Value* current_col_value_lv{nullptr};
639  llvm::Value* frame_start_bound_lv{nullptr};
640  llvm::Value* frame_end_bound_lv{nullptr};
641 
642  if (window_func->hasRangeModeFraming()) {
643  CHECK(window_func_context->getOrderKeyColumnBuffers().size() == 1);
644  CHECK(window_func->getOrderKeys().size() == 1UL);
645  CHECK(window_func_context->getOrderKeyColumnBuffers().size() == 1UL);
646  const auto order_key_ti = window_func->getOrderKeys().front()->get_type_info();
647  const auto order_key_size = order_key_ti.get_size();
648  size_t order_key_size_in_byte = order_key_size * 8;
649  order_col_type_name = get_col_type_name_by_size(
650  order_key_size,
651  window_func_context->getOrderKeyColumnBufferTypes().front().is_fp());
652 
653  // load column value of the current row (of ordering column)
654  auto rowid_in_partition_lv =
655  code_generator.codegenWindowPosition(window_func_context, current_row_pos_lv);
656  auto current_col_value_ptr_lv = cgen_state_->ir_builder_.CreateGEP(
657  get_int_type(order_key_size_in_byte, cgen_state_->context_),
658  order_key_buf_ptr_lv,
659  rowid_in_partition_lv);
660  current_col_value_lv = cgen_state_->ir_builder_.CreateLoad(
661  current_col_value_ptr_lv->getType()->getPointerElementType(),
662  current_col_value_ptr_lv,
663  "current_col_value");
664  }
665 
666  // compute frame start depending on the bound type
667  if (frame_start_bound->getBoundType() == SqlWindowFrameBoundType::UNBOUNDED_PRECEDING) {
668  // frame starts at the first row of the partition
669  frame_start_bound_lv = cgen_state_->llInt((int64_t)0);
670  } else if (frame_start_bound->getBoundType() ==
672  // frame starts at the position before X rows of the current row
673  CHECK(frame_start_bound_expr_lv);
674  if (window_func->hasRowModeFraming()) {
675  frame_start_bound_lv = cgen_state_->emitCall("compute_row_mode_start_index_sub",
676  {current_row_pos_lv,
677  current_partition_start_offset_lv,
678  frame_start_bound_expr_lv});
679  } else {
680  CHECK(window_func->hasRangeModeFraming());
681  if (frame_start_bound->getBoundExpr()->get_type_info().is_date() ||
682  frame_start_bound->getBoundExpr()->get_type_info().is_timestamp()) {
683  std::string lower_bound_func_name{"compute_"};
684  lower_bound_func_name.append(order_col_type_name);
685  lower_bound_func_name.append("_lower_bound_from_ordered_index_for_timeinterval");
686  frame_start_bound_lv = cgen_state_->emitCall(
687  lower_bound_func_name,
688  {num_elem_current_partition_lv,
689  frame_start_bound_expr_lv,
690  order_key_buf_ptr_lv,
691  target_partition_rowid_ptr_lv,
692  target_partition_sorted_rowid_ptr_lv,
693  cgen_state_->castToTypeIn(order_key_col_null_val_lv, 64),
694  null_start_pos_lv,
695  null_end_pos_lv});
696  } else {
697  std::string lower_bound_func_name{"range_mode_"};
698  lower_bound_func_name.append(order_col_type_name);
699  lower_bound_func_name.append("_sub_frame_lower_bound");
700  frame_start_bound_lv =
701  cgen_state_->emitCall(lower_bound_func_name,
702  {num_elem_current_partition_lv,
703  current_col_value_lv,
704  order_key_buf_ptr_lv,
705  target_partition_rowid_ptr_lv,
706  target_partition_sorted_rowid_ptr_lv,
707  frame_start_bound_expr_lv,
708  order_key_col_null_val_lv,
709  null_start_pos_lv,
710  null_end_pos_lv});
711  }
712  }
713  } else if (frame_start_bound->getBoundType() == SqlWindowFrameBoundType::CURRENT_ROW) {
714  // frame start at the current row
715  if (window_func->hasRowModeFraming()) {
716  frame_start_bound_lv = cgen_state_->emitCall("compute_row_mode_start_index_sub",
717  {current_row_pos_lv,
718  current_partition_start_offset_lv,
719  cgen_state_->llInt(((int64_t)0))});
720  } else {
721  CHECK(window_func->hasRangeModeFraming());
722  std::string lower_bound_func_name{"compute_"};
723  lower_bound_func_name.append(order_col_type_name);
724  lower_bound_func_name.append("_lower_bound_from_ordered_index");
725  frame_start_bound_lv = cgen_state_->emitCall(lower_bound_func_name,
726  {num_elem_current_partition_lv,
727  current_col_value_lv,
728  order_key_buf_ptr_lv,
729  target_partition_rowid_ptr_lv,
730  target_partition_sorted_rowid_ptr_lv,
731  order_key_col_null_val_lv,
732  null_start_pos_lv,
733  null_end_pos_lv});
734  }
735  } else if (frame_start_bound->getBoundType() ==
737  // frame start at the position after X rows of the current row
738  CHECK(frame_start_bound_expr_lv);
739  if (window_func->hasRowModeFraming()) {
740  frame_start_bound_lv = cgen_state_->emitCall("compute_row_mode_start_index_add",
741  {current_row_pos_lv,
742  current_partition_start_offset_lv,
743  frame_start_bound_expr_lv,
744  num_elem_current_partition_lv});
745  } else {
746  CHECK(window_func->hasRangeModeFraming());
747  if (frame_start_bound->getBoundExpr()->get_type_info().is_date() ||
748  frame_start_bound->getBoundExpr()->get_type_info().is_timestamp()) {
749  std::string lower_bound_func_name{"compute_"};
750  lower_bound_func_name.append(order_col_type_name);
751  lower_bound_func_name.append("_lower_bound_from_ordered_index_for_timeinterval");
752  frame_start_bound_lv = cgen_state_->emitCall(
753  lower_bound_func_name,
754  {num_elem_current_partition_lv,
755  frame_start_bound_expr_lv,
756  order_key_buf_ptr_lv,
757  target_partition_rowid_ptr_lv,
758  target_partition_sorted_rowid_ptr_lv,
759  cgen_state_->castToTypeIn(order_key_col_null_val_lv, 64),
760  null_start_pos_lv,
761  null_end_pos_lv});
762  } else {
763  std::string lower_bound_func_name{"range_mode_"};
764  lower_bound_func_name.append(order_col_type_name);
765  lower_bound_func_name.append("_add_frame_lower_bound");
766  frame_start_bound_lv =
767  cgen_state_->emitCall(lower_bound_func_name,
768  {num_elem_current_partition_lv,
769  current_col_value_lv,
770  order_key_buf_ptr_lv,
771  target_partition_rowid_ptr_lv,
772  target_partition_sorted_rowid_ptr_lv,
773  frame_start_bound_expr_lv,
774  order_key_col_null_val_lv,
775  null_start_pos_lv,
776  null_end_pos_lv});
777  }
778  }
779  } else {
780  CHECK(false) << "frame start cannot be UNBOUNDED FOLLOWING";
781  }
782 
783  // compute frame end
785  // frame ends at the first row of the partition
786  CHECK(false) << "frame end cannot be UNBOUNDED PRECEDING";
787  } else if (frame_end_bound->getBoundType() == SqlWindowFrameBoundType::EXPR_PRECEDING) {
788  // frame ends at the position X rows before the current row
789  CHECK(frame_end_bound_expr_lv);
790  if (window_func->hasRowModeFraming()) {
791  frame_end_bound_lv = cgen_state_->emitCall("compute_row_mode_end_index_sub",
792  {current_row_pos_lv,
793  current_partition_start_offset_lv,
794  frame_end_bound_expr_lv});
795  } else {
796  CHECK(window_func->hasRangeModeFraming());
797  if (frame_end_bound->getBoundExpr()->get_type_info().is_date() ||
798  frame_end_bound->getBoundExpr()->get_type_info().is_timestamp()) {
799  std::string upper_bound_func_name{"compute_"};
800  upper_bound_func_name.append(order_col_type_name);
801  upper_bound_func_name.append("_upper_bound_from_ordered_index_for_timeinterval");
802  frame_end_bound_lv = cgen_state_->emitCall(
803  upper_bound_func_name,
804  {num_elem_current_partition_lv,
805  frame_end_bound_expr_lv,
806  order_key_buf_ptr_lv,
807  target_partition_rowid_ptr_lv,
808  target_partition_sorted_rowid_ptr_lv,
809  cgen_state_->castToTypeIn(order_key_col_null_val_lv, 64),
810  null_start_pos_lv,
811  null_end_pos_lv});
812  } else {
813  std::string upper_bound_func_name{"range_mode_"};
814  upper_bound_func_name.append(order_col_type_name);
815  upper_bound_func_name.append("_sub_frame_upper_bound");
816  frame_end_bound_lv = cgen_state_->emitCall(upper_bound_func_name,
817  {num_elem_current_partition_lv,
818  current_col_value_lv,
819  order_key_buf_ptr_lv,
820  target_partition_rowid_ptr_lv,
821  target_partition_sorted_rowid_ptr_lv,
822  frame_end_bound_expr_lv,
823  order_key_col_null_val_lv,
824  null_start_pos_lv,
825  null_end_pos_lv});
826  }
827  }
828  } else if (frame_end_bound->getBoundType() == SqlWindowFrameBoundType::CURRENT_ROW) {
829  // frame ends at the current row
830  if (window_func->hasRowModeFraming()) {
831  frame_end_bound_lv = cgen_state_->emitCall("compute_row_mode_end_index_sub",
832  {current_row_pos_lv,
833  current_partition_start_offset_lv,
834  cgen_state_->llInt((int64_t)0)});
835  } else {
836  CHECK(window_func->hasRangeModeFraming());
837  std::string upper_bound_func_name{"compute_"};
838  upper_bound_func_name.append(order_col_type_name);
839  upper_bound_func_name.append("_upper_bound_from_ordered_index");
840  frame_end_bound_lv = cgen_state_->emitCall(upper_bound_func_name,
841  {num_elem_current_partition_lv,
842  current_col_value_lv,
843  order_key_buf_ptr_lv,
844  target_partition_rowid_ptr_lv,
845  target_partition_sorted_rowid_ptr_lv,
846  order_key_col_null_val_lv,
847  null_start_pos_lv,
848  null_end_pos_lv});
849  }
850  } else if (frame_end_bound->getBoundType() == SqlWindowFrameBoundType::EXPR_FOLLOWING) {
851  // frame ends at the position X rows after the current row
852  CHECK(frame_end_bound_expr_lv);
853  if (window_func->hasRowModeFraming()) {
854  frame_end_bound_lv = cgen_state_->emitCall("compute_row_mode_end_index_add",
855  {current_row_pos_lv,
856  current_partition_start_offset_lv,
857  frame_end_bound_expr_lv,
858  num_elem_current_partition_lv});
859  } else {
860  CHECK(window_func->hasRangeModeFraming());
861  if (frame_end_bound->getBoundExpr()->get_type_info().is_date() ||
862  frame_end_bound->getBoundExpr()->get_type_info().is_timestamp()) {
863  std::string upper_bound_func_name{"compute_"};
864  upper_bound_func_name.append(order_col_type_name);
865  upper_bound_func_name.append("_upper_bound_from_ordered_index_for_timeinterval");
866  frame_end_bound_lv = cgen_state_->emitCall(
867  upper_bound_func_name,
868  {num_elem_current_partition_lv,
869  frame_end_bound_expr_lv,
870  order_key_buf_ptr_lv,
871  target_partition_rowid_ptr_lv,
872  target_partition_sorted_rowid_ptr_lv,
873  cgen_state_->castToTypeIn(order_key_col_null_val_lv, 64),
874  null_start_pos_lv,
875  null_end_pos_lv});
876  } else {
877  std::string upper_bound_func_name{"range_mode_"};
878  upper_bound_func_name.append(order_col_type_name);
879  upper_bound_func_name.append("_add_frame_upper_bound");
880  frame_end_bound_lv = cgen_state_->emitCall(upper_bound_func_name,
881  {num_elem_current_partition_lv,
882  current_col_value_lv,
883  order_key_buf_ptr_lv,
884  target_partition_rowid_ptr_lv,
885  target_partition_sorted_rowid_ptr_lv,
886  frame_end_bound_expr_lv,
887  order_key_col_null_val_lv,
888  null_start_pos_lv,
889  null_end_pos_lv});
890  }
891  }
892  } else {
893  // frame ends at the last row of the partition
894  CHECK(frame_end_bound->getBoundType() ==
896  frame_end_bound_lv = num_elem_current_partition_lv;
897  }
898  CHECK(frame_start_bound_lv);
899  CHECK(frame_end_bound_lv);
900  return std::make_pair(frame_start_bound_lv, frame_end_bound_lv);
901 }
902 
903 llvm::Value* Executor::codegenWindowFunctionAggregateCalls(llvm::Value* aggregate_state,
904  const CompilationOptions& co) {
905  AUTOMATIC_IR_METADATA(cgen_state_.get());
906  const auto window_func_context =
908  const auto window_func = window_func_context->getWindowFunction();
909  const auto window_func_ti = get_adjusted_window_type_info(window_func);
910  const auto window_func_null_val =
911  window_func_ti.is_fp()
912  ? cgen_state_->inlineFpNull(window_func_ti)
913  : cgen_state_->castToTypeIn(cgen_state_->inlineIntNull(window_func_ti), 64);
914  const auto& args = window_func->getArgs();
915  llvm::Value* crt_val;
916  CodeGenerator code_generator(this);
917  if (args.empty()) {
918  CHECK(window_func->getKind() == SqlWindowFunctionKind::COUNT);
919  crt_val = cgen_state_->llInt(int64_t(1));
920  } else {
921  const auto arg_lvs = code_generator.codegen(args.front().get(), true, co);
922  CHECK_EQ(arg_lvs.size(), size_t(1));
923  if (window_func->getKind() == SqlWindowFunctionKind::SUM && !window_func_ti.is_fp()) {
924  crt_val = code_generator.codegenCastBetweenIntTypes(
925  arg_lvs.front(), args.front()->get_type_info(), window_func_ti, false);
926  } else {
927  crt_val = window_func_ti.get_type() == kFLOAT
928  ? arg_lvs.front()
929  : cgen_state_->castToTypeIn(arg_lvs.front(), 64);
930  }
931  }
932  if (window_func_context->needsToBuildAggregateTree()) {
933  // compute an aggregated value for each row of the window frame by using segment tree
934  // when constructing a window context, we build a necessary segment tree for it
935  // and use the tree array (so called `aggregate tree`) to query the aggregated value
936  // of the specific window frame
937  // we fall back to the non-framing window func evaluation logic if an input
938  // of the window function can be an empty one
939  const auto pi64_type =
940  llvm::PointerType::get(get_int_type(64, cgen_state_->context_), 0);
941  const auto ppi64_type = llvm::PointerType::get(pi64_type, 0);
942  const auto pi32_type =
943  llvm::PointerType::get(get_int_type(32, cgen_state_->context_), 0);
944 
945  // codegen frame bound expr if necessary
946  const auto frame_start_bound = window_func->getFrameStartBound();
947  const auto frame_end_bound = window_func->getFrameEndBound();
948  auto frame_start_bound_expr_lv =
949  codegenFrameBoundExpr(window_func, frame_start_bound, code_generator, co);
950  auto frame_end_bound_expr_lv =
951  codegenFrameBoundExpr(window_func, frame_end_bound, code_generator, co);
952  CHECK(frame_start_bound_expr_lv);
953  CHECK(frame_end_bound_expr_lv);
954 
955  // compute aggregated value over the computed frame range
956  auto current_row_pos_lv = code_generator.posArg(nullptr);
957  auto partition_index_lv =
958  codegenCurrentPartitionIndex(window_func_context, current_row_pos_lv);
959 
960  // ordering column buffer
961  const auto target_col_ti = window_func->getArgs().front()->get_type_info();
962  const auto target_col_size = target_col_ti.get_size();
963  const auto col_type_name =
964  get_col_type_name_by_size(target_col_size, target_col_ti.is_fp());
965 
966  // partial sum of # elems of partitions
967  auto partition_start_offset_buf_lv = cgen_state_->llInt(
968  reinterpret_cast<int64_t>(window_func_context->partitionStartOffset()));
969  auto partition_start_offset_ptr_lv =
970  cgen_state_->ir_builder_.CreateIntToPtr(partition_start_offset_buf_lv, pi64_type);
971 
972  // get start offset of the current partition
973  auto current_partition_start_offset_ptr_lv =
974  cgen_state_->ir_builder_.CreateGEP(get_int_type(64, cgen_state_->context_),
975  partition_start_offset_ptr_lv,
976  partition_index_lv);
977  auto current_partition_start_offset_lv = cgen_state_->ir_builder_.CreateLoad(
978  current_partition_start_offset_ptr_lv->getType()->getPointerElementType(),
979  current_partition_start_offset_ptr_lv);
980 
981  // row_id buf of the current partition
982  const auto partition_rowid_buf_lv =
983  cgen_state_->llInt(reinterpret_cast<int64_t>(window_func_context->payload()));
984  const auto partition_rowid_ptr_lv =
985  cgen_state_->ir_builder_.CreateIntToPtr(partition_rowid_buf_lv, pi32_type);
986  auto target_partition_rowid_ptr_lv =
987  cgen_state_->ir_builder_.CreateGEP(get_int_type(32, cgen_state_->context_),
988  partition_rowid_ptr_lv,
989  current_partition_start_offset_lv);
990 
991  // row_id buf of ordered current partition
992  const auto sorted_rowid_lv = cgen_state_->llInt(
993  reinterpret_cast<int64_t>(window_func_context->sortedPartition()));
994  const auto sorted_rowid_ptr_lv =
995  cgen_state_->ir_builder_.CreateIntToPtr(sorted_rowid_lv, pi64_type);
996  auto target_partition_sorted_rowid_ptr_lv =
997  cgen_state_->ir_builder_.CreateGEP(get_int_type(64, cgen_state_->context_),
998  sorted_rowid_ptr_lv,
999  current_partition_start_offset_lv);
1000 
1001  // # elems per partition
1002  const auto partition_count_buf =
1003  cgen_state_->llInt(reinterpret_cast<int64_t>(window_func_context->counts()));
1004  auto partition_count_buf_ptr_lv =
1005  cgen_state_->ir_builder_.CreateIntToPtr(partition_count_buf, pi32_type);
1006 
1007  // # elems of the given partition
1008  const auto num_elem_current_partition_ptr =
1009  cgen_state_->ir_builder_.CreateGEP(get_int_type(32, cgen_state_->context_),
1010  partition_count_buf_ptr_lv,
1011  partition_index_lv);
1012  auto num_elem_current_partition_lv = cgen_state_->castToTypeIn(
1013  cgen_state_->ir_builder_.CreateLoad(
1014  num_elem_current_partition_ptr->getType()->getPointerElementType(),
1015  num_elem_current_partition_ptr),
1016  64);
1017 
1018  const auto order_key_ti = window_func->getOrderKeys().front()->get_type_info();
1019  const auto order_key_size = order_key_ti.get_size();
1020  const auto order_col_type_name = get_col_type_name_by_size(
1021  order_key_size,
1022  window_func_context->getOrderKeyColumnBufferTypes().front().is_fp());
1023  size_t order_key_size_in_byte = order_key_size * 8;
1024 
1025  const auto order_key_buf_type = llvm::PointerType::get(
1026  get_int_type(order_key_size_in_byte, cgen_state_->context_), 0);
1027  const auto order_key_buf = cgen_state_->llInt(reinterpret_cast<int64_t>(
1028  window_func_context->getOrderKeyColumnBuffers().front()));
1029  auto order_key_buf_ptr_lv =
1030  cgen_state_->ir_builder_.CreateIntToPtr(order_key_buf, order_key_buf_type);
1031 
1032  // null value of the ordering column
1033  const auto order_key_buf_ti =
1034  window_func_context->getOrderKeyColumnBufferTypes().front();
1035  llvm::Value* order_key_col_null_val_lv{nullptr};
1036  switch (order_key_buf_ti.get_type()) {
1037  case kDATE:
1038  case kTIME:
1039  case kTIMESTAMP: {
1040  switch (order_key_buf_ti.get_size()) {
1041  case 1: {
1042  order_key_col_null_val_lv =
1043  cgen_state_->inlineNull(SQLTypeInfo(SQLTypes::kTINYINT));
1044  break;
1045  }
1046  case 2: {
1047  order_key_col_null_val_lv =
1048  cgen_state_->inlineNull(SQLTypeInfo(SQLTypes::kSMALLINT));
1049  break;
1050  }
1051  case 4: {
1052  order_key_col_null_val_lv =
1053  cgen_state_->inlineNull(SQLTypeInfo(SQLTypes::kINT));
1054  break;
1055  }
1056  case 8: {
1057  order_key_col_null_val_lv =
1058  cgen_state_->inlineNull(SQLTypeInfo(SQLTypes::kBIGINT));
1059  break;
1060  }
1061  default:
1062  break;
1063  }
1064  break;
1065  }
1066  default: {
1067  order_key_col_null_val_lv = cgen_state_->inlineNull(order_key_buf_ti);
1068  break;
1069  }
1070  }
1071 
1072  // null range of the aggregate tree
1073  const auto null_start_pos_buf = cgen_state_->llInt(
1074  reinterpret_cast<int64_t>(window_func_context->getNullValueStartPos()));
1075  const auto null_start_pos_buf_ptr =
1076  cgen_state_->ir_builder_.CreateIntToPtr(null_start_pos_buf, pi64_type);
1077  const auto null_start_pos_ptr =
1078  cgen_state_->ir_builder_.CreateGEP(get_int_type(64, cgen_state_->context_),
1079  null_start_pos_buf_ptr,
1080  partition_index_lv);
1081  auto null_start_pos_lv = cgen_state_->ir_builder_.CreateLoad(
1082  null_start_pos_ptr->getType()->getPointerElementType(),
1083  null_start_pos_ptr,
1084  "null_start_pos");
1085  const auto null_end_pos_buf = cgen_state_->llInt(
1086  reinterpret_cast<int64_t>(window_func_context->getNullValueEndPos()));
1087  const auto null_end_pos_buf_ptr =
1088  cgen_state_->ir_builder_.CreateIntToPtr(null_end_pos_buf, pi64_type);
1089  const auto null_end_pos_ptr =
1090  cgen_state_->ir_builder_.CreateGEP(get_int_type(64, cgen_state_->context_),
1091  null_end_pos_buf_ptr,
1092  partition_index_lv);
1093  auto null_end_pos_lv = cgen_state_->ir_builder_.CreateLoad(
1094  null_end_pos_ptr->getType()->getPointerElementType(),
1095  null_end_pos_ptr,
1096  "null_end_pos");
1097 
1098  llvm::Value* frame_start_bound_lv{nullptr};
1099  llvm::Value* frame_end_bound_lv{nullptr};
1100  std::tie(frame_start_bound_lv, frame_end_bound_lv) =
1101  codegenWindowFrameBound(window_func_context,
1102  frame_start_bound,
1103  frame_end_bound,
1104  current_row_pos_lv,
1105  current_partition_start_offset_lv,
1106  order_key_buf_ptr_lv,
1107  order_key_col_null_val_lv,
1108  frame_start_bound_expr_lv,
1109  frame_end_bound_expr_lv,
1110  num_elem_current_partition_lv,
1111  target_partition_rowid_ptr_lv,
1112  target_partition_sorted_rowid_ptr_lv,
1113  null_start_pos_lv,
1114  null_end_pos_lv,
1115  code_generator);
1116  CHECK(frame_start_bound_lv);
1117  CHECK(frame_end_bound_lv);
1118 
1119  // codegen to send a query with frame bound to aggregate tree searcher
1120  llvm::Value* aggregation_trees_lv{nullptr};
1121  llvm::Value* invalid_val_lv{nullptr};
1122  llvm::Value* null_val_lv{nullptr};
1123  std::string aggregation_tree_search_func_name{"search_"};
1124  std::string aggregation_tree_getter_func_name{"get_"};
1125 
1126  // prepare null values and aggregate_tree getter and searcher depending on
1127  // a type of the ordering column
1128  auto agg_expr_ti = args.front()->get_type_info();
1129  switch (agg_expr_ti.get_type()) {
1130  case SQLTypes::kTINYINT:
1131  case SQLTypes::kSMALLINT:
1132  case SQLTypes::kINT:
1133  case SQLTypes::kBIGINT:
1134  case SQLTypes::kNUMERIC:
1135  case SQLTypes::kDECIMAL: {
1136  if (window_func->getKind() == SqlWindowFunctionKind::MIN) {
1137  invalid_val_lv = cgen_state_->llInt(std::numeric_limits<int64_t>::max());
1138  } else if (window_func->getKind() == SqlWindowFunctionKind::MAX) {
1139  invalid_val_lv = cgen_state_->llInt(std::numeric_limits<int64_t>::lowest());
1140  } else {
1141  invalid_val_lv = cgen_state_->llInt((int64_t)0);
1142  }
1143  null_val_lv = cgen_state_->llInt(inline_int_null_value<int64_t>());
1144  aggregation_tree_search_func_name += "int64_t";
1145  aggregation_tree_getter_func_name += "integer";
1146  break;
1147  }
1148  case SQLTypes::kFLOAT:
1149  case SQLTypes::kDOUBLE: {
1150  if (window_func->getKind() == SqlWindowFunctionKind::MIN) {
1151  invalid_val_lv = cgen_state_->llFp(std::numeric_limits<double>::max());
1152  } else if (window_func->getKind() == SqlWindowFunctionKind::MAX) {
1153  invalid_val_lv = cgen_state_->llFp(std::numeric_limits<double>::lowest());
1154  } else {
1155  invalid_val_lv = cgen_state_->llFp((double)0);
1156  }
1157  null_val_lv = cgen_state_->inlineFpNull(SQLTypeInfo(kDOUBLE));
1158  aggregation_tree_search_func_name += "double";
1159  aggregation_tree_getter_func_name += "double";
1160  break;
1161  }
1162  default: {
1163  CHECK(false);
1164  break;
1165  }
1166  }
1167 
1168  // derived aggregation has a different code path
1169  if (window_func->getKind() == SqlWindowFunctionKind::AVG) {
1170  aggregation_tree_search_func_name += "_derived";
1171  aggregation_tree_getter_func_name += "_derived";
1172  }
1173 
1174  // get a buffer holding aggregate trees for each partition
1175  if (agg_expr_ti.is_integer() || agg_expr_ti.is_decimal()) {
1176  if (window_func->getKind() == SqlWindowFunctionKind::AVG) {
1177  aggregation_trees_lv = cgen_state_->llInt(reinterpret_cast<int64_t>(
1178  window_func_context->getDerivedAggregationTreesForIntegerTypeWindowExpr()));
1179  } else {
1180  aggregation_trees_lv = cgen_state_->llInt(reinterpret_cast<int64_t>(
1181  window_func_context->getAggregationTreesForIntegerTypeWindowExpr()));
1182  }
1183  } else if (agg_expr_ti.is_fp()) {
1184  if (window_func->getKind() == SqlWindowFunctionKind::AVG) {
1185  aggregation_trees_lv = cgen_state_->llInt(reinterpret_cast<int64_t>(
1186  window_func_context->getDerivedAggregationTreesForDoubleTypeWindowExpr()));
1187  } else {
1188  aggregation_trees_lv = cgen_state_->llInt(reinterpret_cast<int64_t>(
1189  window_func_context->getAggregationTreesForDoubleTypeWindowExpr()));
1190  }
1191  }
1192 
1193  CHECK(aggregation_trees_lv);
1194  CHECK(invalid_val_lv);
1195  aggregation_tree_search_func_name += "_aggregation_tree";
1196  aggregation_tree_getter_func_name += "_aggregation_tree";
1197 
1198  // get the aggregate tree of the current partition from a window context
1199  auto aggregation_trees_ptr =
1200  cgen_state_->ir_builder_.CreateIntToPtr(aggregation_trees_lv, ppi64_type);
1201  auto target_aggregation_tree_lv = cgen_state_->emitCall(
1202  aggregation_tree_getter_func_name, {aggregation_trees_ptr, partition_index_lv});
1203 
1204  // a depth of segment tree
1205  const auto tree_depth_buf = cgen_state_->llInt(
1206  reinterpret_cast<int64_t>(window_func_context->getAggregateTreeDepth()));
1207  const auto tree_depth_buf_ptr =
1208  cgen_state_->ir_builder_.CreateIntToPtr(tree_depth_buf, pi64_type);
1209  const auto current_partition_tree_depth_buf_ptr = cgen_state_->ir_builder_.CreateGEP(
1210  get_int_type(64, cgen_state_->context_), tree_depth_buf_ptr, partition_index_lv);
1211  const auto current_partition_tree_depth_lv = cgen_state_->ir_builder_.CreateLoad(
1212  current_partition_tree_depth_buf_ptr->getType()->getPointerElementType(),
1213  current_partition_tree_depth_buf_ptr);
1214 
1215  // a fanout of the current partition's segment tree
1216  const auto aggregation_tree_fanout_lv = cgen_state_->llInt(
1217  static_cast<int64_t>(window_func_context->getAggregateTreeFanout()));
1218 
1219  // agg_type
1220  const auto agg_type_lv =
1221  cgen_state_->llInt(static_cast<int32_t>(window_func->getKind()));
1222 
1223  // send a query to the aggregate tree with the frame range:
1224  // `frame_start_bound_lv` ~ `frame_end_bound_lv`
1225  auto res_lv =
1226  cgen_state_->emitCall(aggregation_tree_search_func_name,
1227  {target_aggregation_tree_lv,
1228  frame_start_bound_lv,
1229  frame_end_bound_lv,
1230  current_partition_tree_depth_lv,
1231  aggregation_tree_fanout_lv,
1232  cgen_state_->llBool(agg_expr_ti.is_decimal()),
1233  cgen_state_->llInt((int64_t)agg_expr_ti.get_scale()),
1234  invalid_val_lv,
1235  null_val_lv,
1236  agg_type_lv});
1237 
1238  // handling returned null value if exists
1239  std::string null_handler_func_name{"handle_null_val_"};
1240  std::vector<llvm::Value*> null_handler_args{res_lv, null_val_lv};
1241 
1242  // determine null_handling function's name
1243  if (window_func->getKind() == SqlWindowFunctionKind::AVG) {
1244  // average aggregate function returns a value as a double
1245  // (and our search* function also returns a double)
1246  if (agg_expr_ti.is_fp()) {
1247  // fp type: double null value
1248  null_handler_func_name += "double_double";
1249  } else {
1250  // non-fp type: int64_t null type
1251  null_handler_func_name += "double_int64_t";
1252  }
1253  } else if (agg_expr_ti.is_fp()) {
1254  // fp type: double null value
1255  null_handler_func_name += "double_double";
1256  } else {
1257  // non-fp type: int64_t null type
1258  null_handler_func_name += "int64_t_int64_t";
1259  }
1260  null_handler_func_name += "_window_framing_agg";
1261 
1262  // prepare null_val
1263  if (window_func->getKind() == SqlWindowFunctionKind::COUNT) {
1264  if (agg_expr_ti.is_fp()) {
1265  null_handler_args.push_back(cgen_state_->llFp((double)0));
1266  } else {
1267  null_handler_args.push_back(cgen_state_->llInt((int64_t)0));
1268  }
1269  } else if (window_func->getKind() == SqlWindowFunctionKind::AVG) {
1270  null_handler_args.push_back(cgen_state_->inlineFpNull(SQLTypeInfo(kDOUBLE)));
1271  } else {
1272  null_handler_args.push_back(cgen_state_->castToTypeIn(window_func_null_val, 64));
1273  }
1274  res_lv = cgen_state_->emitCall(null_handler_func_name, null_handler_args);
1275 
1276  // when AGG_TYPE is double, we get a double type return value we expect an integer
1277  // type value for the count aggregation
1278  if (window_func->getKind() == SqlWindowFunctionKind::COUNT && agg_expr_ti.is_fp()) {
1279  return cgen_state_->ir_builder_.CreateFPToSI(
1280  res_lv, get_int_type(64, cgen_state_->context_));
1281  }
1282  return res_lv;
1283  } else {
1284  llvm::Value* multiplicity_lv = nullptr;
1285  const auto agg_name = get_window_agg_name(window_func->getKind(), window_func_ti);
1286  if (args.empty()) {
1287  cgen_state_->emitCall(agg_name, {aggregate_state, crt_val});
1288  } else {
1289  cgen_state_->emitCall(agg_name + "_skip_val",
1290  {aggregate_state, crt_val, window_func_null_val});
1291  }
1292  if (window_func->getKind() == SqlWindowFunctionKind::AVG) {
1293  codegenWindowAvgEpilogue(crt_val, window_func_null_val, multiplicity_lv);
1294  }
1295  return codegenAggregateWindowState();
1296  }
1297 }
1298 
1299 void Executor::codegenWindowAvgEpilogue(llvm::Value* crt_val,
1300  llvm::Value* window_func_null_val,
1301  llvm::Value* multiplicity_lv) {
1302  AUTOMATIC_IR_METADATA(cgen_state_.get());
1303  const auto window_func_context =
1305  const auto window_func = window_func_context->getWindowFunction();
1306  const auto window_func_ti = get_adjusted_window_type_info(window_func);
1307  const auto pi32_type =
1308  llvm::PointerType::get(get_int_type(32, cgen_state_->context_), 0);
1309  const auto pi64_type =
1310  llvm::PointerType::get(get_int_type(64, cgen_state_->context_), 0);
1311  const auto aggregate_state_type =
1312  window_func_ti.get_type() == kFLOAT ? pi32_type : pi64_type;
1313  const auto aggregate_state_count_i64 = cgen_state_->llInt(
1314  reinterpret_cast<const int64_t>(window_func_context->aggregateStateCount()));
1315  auto aggregate_state_count = cgen_state_->ir_builder_.CreateIntToPtr(
1316  aggregate_state_count_i64, aggregate_state_type);
1317  std::string agg_count_func_name = "agg_count";
1318  switch (window_func_ti.get_type()) {
1319  case kFLOAT: {
1320  agg_count_func_name += "_float";
1321  break;
1322  }
1323  case kDOUBLE: {
1324  agg_count_func_name += "_double";
1325  break;
1326  }
1327  default: {
1328  break;
1329  }
1330  }
1331  agg_count_func_name += "_skip_val";
1332  cgen_state_->emitCall(agg_count_func_name,
1333  {aggregate_state_count, crt_val, window_func_null_val});
1334 }
1335 
1337  AUTOMATIC_IR_METADATA(cgen_state_.get());
1338  const auto pi32_type =
1339  llvm::PointerType::get(get_int_type(32, cgen_state_->context_), 0);
1340  const auto pi64_type =
1341  llvm::PointerType::get(get_int_type(64, cgen_state_->context_), 0);
1342  const auto window_func_context =
1344  const Analyzer::WindowFunction* window_func = window_func_context->getWindowFunction();
1345  const auto window_func_ti = get_adjusted_window_type_info(window_func);
1346  const auto aggregate_state_type =
1347  window_func_ti.get_type() == kFLOAT ? pi32_type : pi64_type;
1348  auto aggregate_state = aggregateWindowStatePtr();
1349  if (window_func->getKind() == SqlWindowFunctionKind::AVG) {
1350  const auto aggregate_state_count_i64 = cgen_state_->llInt(
1351  reinterpret_cast<const int64_t>(window_func_context->aggregateStateCount()));
1352  auto aggregate_state_count = cgen_state_->ir_builder_.CreateIntToPtr(
1353  aggregate_state_count_i64, aggregate_state_type);
1354  const auto double_null_lv = cgen_state_->inlineFpNull(SQLTypeInfo(kDOUBLE));
1355  switch (window_func_ti.get_type()) {
1356  case kFLOAT: {
1357  return cgen_state_->emitCall(
1358  "load_avg_float", {aggregate_state, aggregate_state_count, double_null_lv});
1359  }
1360  case kDOUBLE: {
1361  return cgen_state_->emitCall(
1362  "load_avg_double", {aggregate_state, aggregate_state_count, double_null_lv});
1363  }
1364  case kDECIMAL: {
1365  return cgen_state_->emitCall(
1366  "load_avg_decimal",
1367  {aggregate_state,
1368  aggregate_state_count,
1369  double_null_lv,
1370  cgen_state_->llInt<int32_t>(window_func_ti.get_scale())});
1371  }
1372  default: {
1373  return cgen_state_->emitCall(
1374  "load_avg_int", {aggregate_state, aggregate_state_count, double_null_lv});
1375  }
1376  }
1377  }
1378  if (window_func->getKind() == SqlWindowFunctionKind::COUNT) {
1379  return cgen_state_->ir_builder_.CreateLoad(
1380  aggregate_state->getType()->getPointerElementType(), aggregate_state);
1381  }
1382  switch (window_func_ti.get_type()) {
1383  case kFLOAT: {
1384  return cgen_state_->emitCall("load_float", {aggregate_state});
1385  }
1386  case kDOUBLE: {
1387  return cgen_state_->emitCall("load_double", {aggregate_state});
1388  }
1389  default: {
1390  return cgen_state_->ir_builder_.CreateLoad(
1391  aggregate_state->getType()->getPointerElementType(), aggregate_state);
1392  }
1393  }
1394 }
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:2440
#define CHECK_EQ(x, y)
Definition: Logger.h:230
llvm::Value * castToTypeIn(llvm::Value *val, const size_t bit_width)
Definition: CgenState.cpp:152
SqlWindowFunctionKind getKind() const
Definition: Analyzer.h:2406
HOST DEVICE int get_size() const
Definition: sqltypes.h:414
llvm::Value * codegenCurrentPartitionIndex(const WindowFunctionContext *window_func_context, llvm::Value *current_row_pos_lv)
Definition: sqltypes.h:63
bool is_timestamp() const
Definition: sqltypes.h:1020
#define LOG(tag)
Definition: Logger.h:216
bool is_fp() const
Definition: sqltypes.h:604
const std::vector< SQLTypeInfo > & getOrderKeyColumnBufferTypes() const
llvm::Value * posArg(const Analyzer::Expr *) const
Definition: ColumnIR.cpp:550
llvm::Value * aggregateWindowStatePtr()
llvm::Value * codegenWindowFunctionOnFrame(const CompilationOptions &co)
llvm::Type * get_fp_type(const int width, llvm::LLVMContext &context)
HOST DEVICE SQLTypes get_type() const
Definition: sqltypes.h:404
llvm::Type * get_int_type(const int width, llvm::LLVMContext &context)
const std::vector< std::shared_ptr< Analyzer::Expr > > & getOrderKeys() const
Definition: Analyzer.h:2414
static WindowFunctionContext * getActiveWindowFunctionContext(Executor *executor)
std::string get_window_agg_name(const SqlWindowFunctionKind kind, const SQLTypeInfo &window_func_ti)
void codegenWindowAvgEpilogue(llvm::Value *crt_val, llvm::Value *window_func_null_val, llvm::Value *multiplicity_lv)
size_t partitionCount() const
SqlWindowFrameBoundType getBoundType() const
Definition: Analyzer.h:2338
llvm::Value * codegenWindowPosition(const WindowFunctionContext *window_func_context, llvm::Value *pos_arg)
Definition: ColumnIR.cpp:230
static const WindowProjectNodeContext * get(Executor *executor)
const std::vector< std::shared_ptr< Analyzer::Expr > > & getArgs() const
Definition: Analyzer.h:2408
int get_logical_size() const
Definition: sqltypes.h:424
const WindowFunctionContext * activateWindowFunctionContext(Executor *executor, const size_t target_index) const
llvm::Value * codegenCastBetweenIntTypes(llvm::Value *operand_lv, const SQLTypeInfo &operand_ti, const SQLTypeInfo &ti, bool upscale=true)
Definition: CastIR.cpp:342
const Analyzer::Expr * getBoundExpr() const
Definition: Analyzer.h:2340
llvm::ConstantFP * llFp(const float v) const
Definition: CgenState.h:310
#define AUTOMATIC_IR_METADATA(CGENSTATE)
const SQLTypeInfo & get_type_info() const
Definition: Analyzer.h:82
std::vector< llvm::Value * > codegen(const Analyzer::Expr *, const bool fetch_columns, const CompilationOptions &)
Definition: IRCodegen.cpp:30
Definition: sqltypes.h:67
HOST DEVICE EncodingType get_compression() const
Definition: sqltypes.h:412
std::pair< llvm::Value *, llvm::Value * > codegenWindowFrameBound(WindowFunctionContext *window_func_context, const Analyzer::WindowFrame *frame_start_bound, const Analyzer::WindowFrame *frame_end_bound, llvm::Value *current_row_pos_lv, llvm::Value *current_partition_start_offset_lv, llvm::Value *order_key_buf_ptr_lv, llvm::Value *order_key_col_null_val_lv, llvm::Value *frame_start_bound_expr_lv, llvm::Value *frame_end_bound_expr_lv, llvm::Value *num_elem_current_partition_lv, llvm::Value *target_partition_rowid_ptr_lv, llvm::Value *target_partition_sorted_rowid_ptr_lv, llvm::Value *null_start_pos_lv, llvm::Value *null_end_pos_lv, CodeGenerator &code_generator)
void codegenWindowFunctionStateInit(llvm::Value *aggregate_state)
constexpr float inline_fp_null_value< float >()
const std::vector< const int8_t * > & getOrderKeyColumnBuffers() const
constexpr double inline_fp_null_value< double >()
const int64_t * partitionNumCountBuf() const
llvm::Value * toBool(llvm::Value *)
Definition: LogicalIR.cpp:343
SqlWindowFunctionKind
Definition: sqldefs.h:113
llvm::Value * codegenAggregateWindowState()
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:306
llvm::Value * codegenWindowFunctionAggregate(const CompilationOptions &co)
#define CHECK(condition)
Definition: Logger.h:222
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
const Analyzer::WindowFunction * getWindowFunction() const
bool is_dict_encoded_string() const
Definition: sqltypes.h:652
Definition: sqltypes.h:59
llvm::Value * get_null_value_by_size(CgenState *cgen_state, SQLTypeInfo col_ti)
llvm::Value * codegenWindowFunctionAggregateCalls(llvm::Value *aggregate_state, const CompilationOptions &co)
llvm::Value * codegenWindowFunction(const size_t target_index, const CompilationOptions &co)
bool is_date() const
Definition: sqltypes.h:1008
llvm::BasicBlock * codegenWindowResetStateControlFlow()
llvm::Value * get_null_value_by_size_with_encoding(CgenState *cgen_state, SQLTypeInfo col_ti)
SQLTypeInfo get_adjusted_window_type_info(const Analyzer::WindowFunction *window_func)