OmniSciDB  a5dc49c757
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ResultSetReductionJIT.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 "ResultSetReductionJIT.h"
20 
21 #include "CodeGenerator.h"
22 #include "DynamicWatchdog.h"
23 #include "Execute.h"
24 #include "IRCodegenUtils.h"
27 #include "Shared/StringTransform.h"
28 #include "Shared/likely.h"
29 #include "Shared/quantile.h"
30 
31 #include <llvm/Bitcode/BitcodeReader.h>
32 #include <llvm/IR/Function.h>
33 #include <llvm/IR/IRBuilder.h>
34 #include <llvm/IR/Verifier.h>
35 #include <llvm/Support/SourceMgr.h>
36 #include <llvm/Support/raw_os_ostream.h>
37 
38 namespace {
39 
40 // Error code to be returned when the watchdog timer triggers during the reduction.
41 const int32_t WATCHDOG_ERROR{-1};
42 // Error code to be returned when the interrupt is triggered during the reduction.
43 const int32_t INTERRUPT_ERROR{10};
44 // Use the interpreter, not the JIT, for a number of entries lower than the threshold.
45 const size_t INTERP_THRESHOLD{25};
46 
47 // Load the value stored at 'ptr' interpreted as 'ptr_type'.
48 Value* emit_load(Value* ptr, Type ptr_type, Function* function) {
49  return function->add<Load>(
50  function->add<Cast>(Cast::CastOp::BitCast, ptr, ptr_type, ""),
51  ptr->label() + "_loaded");
52 }
53 
54 // Load the value stored at 'ptr' as a 32-bit signed integer.
55 Value* emit_load_i32(Value* ptr, Function* function) {
56  return emit_load(ptr, Type::Int32Ptr, function);
57 }
58 
59 // Load the value stored at 'ptr' as a 64-bit signed integer.
60 Value* emit_load_i64(Value* ptr, Function* function) {
61  return emit_load(ptr, Type::Int64Ptr, function);
62 }
63 
64 // Read a 32- or 64-bit integer stored at 'ptr' and sign extend to 64-bit.
65 Value* emit_read_int_from_buff(Value* ptr, const int8_t compact_sz, Function* function) {
66  switch (compact_sz) {
67  case 8: {
68  return emit_load_i64(ptr, function);
69  }
70  case 4: {
71  const auto loaded_val = emit_load_i32(ptr, function);
72  return function->add<Cast>(Cast::CastOp::SExt, loaded_val, Type::Int64, "");
73  }
74  default: {
75  LOG(FATAL) << "Invalid byte width: " << compact_sz;
76  return nullptr;
77  }
78  }
79 }
80 
81 // Emit a runtime call to accumulate into the 'val_ptr' byte address the 'other_ptr'
82 // value when the type is specified as not null.
83 void emit_aggregate_one_value(const std::string& agg_kind,
84  Value* val_ptr,
85  Value* other_ptr,
86  const size_t chosen_bytes,
87  const TargetInfo& agg_info,
88  Function* ir_reduce_one_entry) {
89  const auto sql_type = get_compact_type(agg_info);
90  const auto dest_name = agg_kind + "_dest";
91  if (sql_type.is_fp()) {
92  if (chosen_bytes == sizeof(float)) {
93  const auto agg = ir_reduce_one_entry->add<Cast>(
94  Cast::CastOp::BitCast, val_ptr, Type::Int32Ptr, dest_name);
95  const auto val = emit_load(other_ptr, Type::FloatPtr, ir_reduce_one_entry);
96  ir_reduce_one_entry->add<Call>(
97  "agg_" + agg_kind + "_float", std::vector<const Value*>{agg, val}, "");
98  } else {
99  CHECK_EQ(chosen_bytes, sizeof(double));
100  const auto agg = ir_reduce_one_entry->add<Cast>(
101  Cast::CastOp::BitCast, val_ptr, Type::Int64Ptr, dest_name);
102  const auto val = emit_load(other_ptr, Type::DoublePtr, ir_reduce_one_entry);
103  ir_reduce_one_entry->add<Call>(
104  "agg_" + agg_kind + "_double", std::vector<const Value*>{agg, val}, "");
105  }
106  } else {
107  if (chosen_bytes == sizeof(int32_t)) {
108  const auto agg = ir_reduce_one_entry->add<Cast>(
109  Cast::CastOp::BitCast, val_ptr, Type::Int32Ptr, dest_name);
110  const auto val = emit_load(other_ptr, Type::Int32Ptr, ir_reduce_one_entry);
111  ir_reduce_one_entry->add<Call>(
112  "agg_" + agg_kind + "_int32", std::vector<const Value*>{agg, val}, "");
113  } else {
114  CHECK_EQ(chosen_bytes, sizeof(int64_t));
115  const auto agg = ir_reduce_one_entry->add<Cast>(
116  Cast::CastOp::BitCast, val_ptr, Type::Int64Ptr, dest_name);
117  const auto val = emit_load(other_ptr, Type::Int64Ptr, ir_reduce_one_entry);
118  ir_reduce_one_entry->add<Call>(
119  "agg_" + agg_kind, std::vector<const Value*>{agg, val}, "");
120  }
121  }
122 }
123 
124 // Same as above, but support nullable types as well.
126  Value* val_ptr,
127  Value* other_ptr,
128  const int64_t init_val,
129  const size_t chosen_bytes,
130  const TargetInfo& agg_info,
131  Function* ir_reduce_one_entry) {
132  const std::string agg_kind = to_lower(toString(get_non_conditional_agg_type(sql_agg)));
133  const auto dest_name = agg_kind + "_dest";
134  if (agg_info.skip_null_val) {
135  const auto sql_type = get_compact_type(agg_info);
136  if (sql_type.is_fp()) {
137  if (chosen_bytes == sizeof(float)) {
138  const auto agg = ir_reduce_one_entry->add<Cast>(
139  Cast::CastOp::BitCast, val_ptr, Type::Int32Ptr, dest_name);
140  const auto val = emit_load(other_ptr, Type::FloatPtr, ir_reduce_one_entry);
141  const auto init_val_lv = ir_reduce_one_entry->addConstant<ConstantFP>(
142  *reinterpret_cast<const float*>(may_alias_ptr(&init_val)), Type::Float);
143  std::vector<const Value*> args{agg, val, init_val_lv};
144  ir_reduce_one_entry->add<Call>("agg_" + agg_kind + "_float_skip_val", args, "");
145  } else {
146  CHECK_EQ(chosen_bytes, sizeof(double));
147  const auto agg = ir_reduce_one_entry->add<Cast>(
148  Cast::CastOp::BitCast, val_ptr, Type::Int64Ptr, dest_name);
149  const auto val = emit_load(other_ptr, Type::DoublePtr, ir_reduce_one_entry);
150  const auto init_val_lv = ir_reduce_one_entry->addConstant<ConstantFP>(
151  *reinterpret_cast<const double*>(may_alias_ptr(&init_val)), Type::Double);
152  ir_reduce_one_entry->add<Call>("agg_" + agg_kind + "_double_skip_val",
153  std::vector<const Value*>{agg, val, init_val_lv},
154  "");
155  }
156  } else {
157  if (chosen_bytes == sizeof(int32_t)) {
158  const auto agg = ir_reduce_one_entry->add<Cast>(
159  Cast::CastOp::BitCast, val_ptr, Type::Int32Ptr, dest_name);
160  const auto val = emit_load(other_ptr, Type::Int32Ptr, ir_reduce_one_entry);
161  const auto init_val_lv =
162  ir_reduce_one_entry->addConstant<ConstantInt>(init_val, Type::Int32);
163  ir_reduce_one_entry->add<Call>("agg_" + agg_kind + "_int32_skip_val",
164  std::vector<const Value*>{agg, val, init_val_lv},
165  "");
166  } else {
167  CHECK_EQ(chosen_bytes, sizeof(int64_t));
168  const auto agg = ir_reduce_one_entry->add<Cast>(
169  Cast::CastOp::BitCast, val_ptr, Type::Int64Ptr, dest_name);
170  const auto val = emit_load(other_ptr, Type::Int64Ptr, ir_reduce_one_entry);
171  const auto init_val_lv =
172  ir_reduce_one_entry->addConstant<ConstantInt>(init_val, Type::Int64);
173  ir_reduce_one_entry->add<Call>("agg_" + agg_kind + "_skip_val",
174  std::vector<const Value*>{agg, val, init_val_lv},
175  "");
176  }
177  }
178  } else {
180  agg_kind, val_ptr, other_ptr, chosen_bytes, agg_info, ir_reduce_one_entry);
181  }
182 }
183 
184 // Emit code to accumulate the 'other_ptr' count into the 'val_ptr' destination.
186  Value* other_ptr,
187  const size_t chosen_bytes,
188  Function* ir_reduce_one_entry) {
189  const auto dest_name = "count_dest";
190  if (chosen_bytes == sizeof(int32_t)) {
191  const auto agg = ir_reduce_one_entry->add<Cast>(
192  Cast::CastOp::BitCast, val_ptr, Type::Int32Ptr, dest_name);
193  const auto val = emit_load(other_ptr, Type::Int32Ptr, ir_reduce_one_entry);
194  ir_reduce_one_entry->add<Call>(
195  "agg_sum_int32", std::vector<const Value*>{agg, val}, "");
196  } else {
197  CHECK_EQ(chosen_bytes, sizeof(int64_t));
198  const auto agg = ir_reduce_one_entry->add<Cast>(
199  Cast::CastOp::BitCast, val_ptr, Type::Int64Ptr, dest_name);
200  const auto val = emit_load(other_ptr, Type::Int64Ptr, ir_reduce_one_entry);
201  ir_reduce_one_entry->add<Call>("agg_sum", std::vector<const Value*>{agg, val}, "");
202  }
203 }
204 
205 // Emit code to load the value stored at the 'other_pi8' as an integer of the given width
206 // 'chosen_bytes' and write it to the 'slot_pi8' destination only if necessary (the
207 // existing value at destination is the initialization value).
209  Value* other_pi8,
210  const int64_t init_val,
211  const size_t chosen_bytes,
212  Function* ir_reduce_one_entry) {
213  const auto func_name = "write_projection_int" + std::to_string(chosen_bytes * 8);
214  if (chosen_bytes == sizeof(int32_t)) {
215  const auto proj_val = emit_load_i32(other_pi8, ir_reduce_one_entry);
216  ir_reduce_one_entry->add<Call>(
217  func_name,
218  std::vector<const Value*>{
219  slot_pi8,
220  proj_val,
221  ir_reduce_one_entry->addConstant<ConstantInt>(init_val, Type::Int64)},
222  "");
223  } else {
224  CHECK_EQ(chosen_bytes, sizeof(int64_t));
225  const auto proj_val = emit_load_i64(other_pi8, ir_reduce_one_entry);
226  ir_reduce_one_entry->add<Call>(
227  func_name,
228  std::vector<const Value*>{
229  slot_pi8,
230  proj_val,
231  ir_reduce_one_entry->addConstant<ConstantInt>(init_val, Type::Int64)},
232  "");
233  }
234 }
235 
236 // Emit code to load the value stored at the 'other_pi8' as an integer of the given width
237 // 'chosen_bytes' and write it to the 'slot_pi8' destination only if necessary (the
238 // existing value at destination is the initialization value).
240  Value* other_pi8,
241  const int64_t init_val,
242  const size_t chosen_bytes,
243  Function* ir_reduce_one_entry) {
244  if (chosen_bytes == sizeof(int32_t)) {
245  const auto func_name = "checked_single_agg_id_int32";
246  const auto proj_val = emit_load_i32(other_pi8, ir_reduce_one_entry);
247  const auto slot_pi32 = ir_reduce_one_entry->add<Cast>(
248  Cast::CastOp::BitCast, slot_pi8, Type::Int32Ptr, "");
249  return ir_reduce_one_entry->add<Call>(
250  func_name,
251  Type::Int32,
252  std::vector<const Value*>{
253  slot_pi32,
254  proj_val,
255  ir_reduce_one_entry->addConstant<ConstantInt>(init_val, Type::Int32)},
256  "");
257  } else {
258  const auto func_name = "checked_single_agg_id";
259  CHECK_EQ(chosen_bytes, sizeof(int64_t));
260  const auto proj_val = emit_load_i64(other_pi8, ir_reduce_one_entry);
261  const auto slot_pi64 = ir_reduce_one_entry->add<Cast>(
262  Cast::CastOp::BitCast, slot_pi8, Type::Int64Ptr, "");
263 
264  return ir_reduce_one_entry->add<Call>(
265  func_name,
266  Type::Int32,
267  std::vector<const Value*>{
268  slot_pi64,
269  proj_val,
270  ir_reduce_one_entry->addConstant<ConstantInt>(init_val, Type::Int64)},
271  "");
272  }
273 }
274 
275 std::unique_ptr<Function> create_function(
276  const std::string name,
277  const std::vector<Function::NamedArg>& arg_types,
278  const Type ret_type,
279  const bool always_inline) {
280  return std::make_unique<Function>(name, arg_types, ret_type, always_inline);
281 }
282 
283 // Create the declaration for the 'is_empty_entry' function. Use private linkage since
284 // it's a helper only called from the generated code and mark it as always inline.
285 std::unique_ptr<Function> setup_is_empty_entry(ReductionCode* reduction_code) {
286  return create_function(
287  "is_empty_entry", {{"row_ptr", Type::Int8Ptr}}, Type::Int1, /*always_inline=*/true);
288 }
289 
290 // Create the declaration for the 'reduce_one_entry' helper.
291 std::unique_ptr<Function> setup_reduce_one_entry(ReductionCode* reduction_code,
292  const QueryDescriptionType hash_type) {
293  std::string this_ptr_name;
294  std::string that_ptr_name;
295  switch (hash_type) {
297  this_ptr_name = "this_targets_ptr";
298  that_ptr_name = "that_targets_ptr";
299  break;
300  }
303  this_ptr_name = "this_row_ptr";
304  that_ptr_name = "that_row_ptr";
305  break;
306  }
307  default: {
308  LOG(FATAL) << "Unexpected query description type";
309  }
310  }
311  return create_function("reduce_one_entry",
312  {{this_ptr_name, Type::Int8Ptr},
313  {that_ptr_name, Type::Int8Ptr},
314  {"this_qmd", Type::VoidPtr},
315  {"that_qmd", Type::VoidPtr},
316  {"serialized_varlen_buffer_arg", Type::VoidPtr}},
317  Type::Int32,
318  /*always_inline=*/true);
319 }
320 
321 // Create the declaration for the 'reduce_one_entry_idx' helper.
322 std::unique_ptr<Function> setup_reduce_one_entry_idx(ReductionCode* reduction_code) {
323  return create_function("reduce_one_entry_idx",
324  {{"this_buff", Type::Int8Ptr},
325  {"that_buff", Type::Int8Ptr},
326  {"that_entry_idx", Type::Int32},
327  {"that_entry_count", Type::Int32},
328  {"this_qmd_handle", Type::VoidPtr},
329  {"that_qmd_handle", Type::VoidPtr},
330  {"serialized_varlen_buffer", Type::VoidPtr}},
331  Type::Int32,
332  /*always_inline=*/true);
333 }
334 
335 // Create the declaration for the 'reduce_loop' entry point. Use external linkage, this is
336 // the public API of the generated code directly used from result set reduction.
337 std::unique_ptr<Function> setup_reduce_loop(ReductionCode* reduction_code) {
338  return create_function("reduce_loop",
339  {{"this_buff", Type::Int8Ptr},
340  {"that_buff", Type::Int8Ptr},
341  {"start_index", Type::Int32},
342  {"end_index", Type::Int32},
343  {"that_entry_count", Type::Int32},
344  {"this_qmd_handle", Type::VoidPtr},
345  {"that_qmd_handle", Type::VoidPtr},
346  {"serialized_varlen_buffer", Type::VoidPtr}},
347  Type::Int32,
348  /*always_inline=*/false);
349 }
350 
351 llvm::Function* create_llvm_function(const Function* function, CgenState* cgen_state) {
352  AUTOMATIC_IR_METADATA(cgen_state);
353  auto& ctx = cgen_state->context_;
354  std::vector<llvm::Type*> parameter_types;
355  const auto& arg_types = function->arg_types();
356  for (const auto& named_arg : arg_types) {
357  CHECK(named_arg.type != Type::Void);
358  parameter_types.push_back(llvm_type(named_arg.type, ctx));
359  }
360  const auto func_type = llvm::FunctionType::get(
361  llvm_type(function->ret_type(), ctx), parameter_types, false);
362  const auto linkage = function->always_inline() ? llvm::Function::PrivateLinkage
363  : llvm::Function::ExternalLinkage;
364  auto func =
365  llvm::Function::Create(func_type, linkage, function->name(), cgen_state->module_);
366  const auto arg_it = func->arg_begin();
367  for (size_t i = 0; i < arg_types.size(); ++i) {
368  const auto arg = &*(arg_it + i);
369  arg->setName(arg_types[i].name);
370  }
371  if (function->always_inline()) {
373  }
374  return func;
375 }
376 
377 // Setup the reduction function and helpers declarations, create a module and a code
378 // generation state object.
379 ReductionCode setup_functions_ir(const QueryDescriptionType hash_type) {
380  ReductionCode reduction_code{};
381  reduction_code.ir_is_empty = setup_is_empty_entry(&reduction_code);
382  reduction_code.ir_reduce_one_entry = setup_reduce_one_entry(&reduction_code, hash_type);
383  reduction_code.ir_reduce_one_entry_idx = setup_reduce_one_entry_idx(&reduction_code);
384  reduction_code.ir_reduce_loop = setup_reduce_loop(&reduction_code);
385  return reduction_code;
386 }
387 
388 bool is_aggregate_query(const QueryDescriptionType hash_type) {
389  return hash_type == QueryDescriptionType::GroupByBaselineHash ||
392 }
393 
394 // Variable length sample fast path (no serialized variable length buffer).
395 void varlen_buffer_sample(int8_t* this_ptr1,
396  int8_t* this_ptr2,
397  const int8_t* that_ptr1,
398  const int8_t* that_ptr2,
399  const int64_t init_val) {
400  const auto rhs_proj_col = *reinterpret_cast<const int64_t*>(that_ptr1);
401  if (rhs_proj_col != init_val) {
402  *reinterpret_cast<int64_t*>(this_ptr1) = rhs_proj_col;
403  }
404  CHECK(this_ptr2 && that_ptr2);
405  *reinterpret_cast<int64_t*>(this_ptr2) = *reinterpret_cast<const int64_t*>(that_ptr2);
406 }
407 
408 } // namespace
409 
411  const void* serialized_varlen_buffer_handle,
412  int8_t* this_ptr1,
413  int8_t* this_ptr2,
414  const int8_t* that_ptr1,
415  const int8_t* that_ptr2,
416  const int64_t init_val,
417  const int64_t length_to_elems) {
418  if (!serialized_varlen_buffer_handle) {
419  varlen_buffer_sample(this_ptr1, this_ptr2, that_ptr1, that_ptr2, init_val);
420  return;
421  }
422  const auto& serialized_varlen_buffer =
423  *reinterpret_cast<const std::vector<std::string>*>(serialized_varlen_buffer_handle);
424  if (!serialized_varlen_buffer.empty()) {
425  const auto rhs_proj_col = *reinterpret_cast<const int64_t*>(that_ptr1);
426  CHECK_LT(static_cast<size_t>(rhs_proj_col), serialized_varlen_buffer.size());
427  const auto& varlen_bytes_str = serialized_varlen_buffer[rhs_proj_col];
428  const auto str_ptr = reinterpret_cast<const int8_t*>(varlen_bytes_str.c_str());
429  *reinterpret_cast<int64_t*>(this_ptr1) = reinterpret_cast<const int64_t>(str_ptr);
430  *reinterpret_cast<int64_t*>(this_ptr2) =
431  static_cast<int64_t>(varlen_bytes_str.size() / length_to_elems);
432  } else {
433  varlen_buffer_sample(this_ptr1, this_ptr2, that_ptr1, that_ptr2, init_val);
434  }
435 }
436 
437 // Wrappers to be called from the generated code, sharing implementation with the rest of
438 // the system.
439 
441  const int64_t new_set_handle,
442  const int64_t old_set_handle,
443  const void* that_qmd_handle,
444  const void* this_qmd_handle,
445  const int64_t target_logical_idx) {
446  const auto that_qmd = reinterpret_cast<const QueryMemoryDescriptor*>(that_qmd_handle);
447  const auto this_qmd = reinterpret_cast<const QueryMemoryDescriptor*>(this_qmd_handle);
448  const auto& new_count_distinct_desc =
449  that_qmd->getCountDistinctDescriptor(target_logical_idx);
450  const auto& old_count_distinct_desc =
451  this_qmd->getCountDistinctDescriptor(target_logical_idx);
452  CHECK(old_count_distinct_desc.impl_type_ != CountDistinctImplType::Invalid);
453  CHECK(old_count_distinct_desc.impl_type_ == new_count_distinct_desc.impl_type_);
455  new_set_handle, old_set_handle, new_count_distinct_desc, old_count_distinct_desc);
456 }
457 
458 extern "C" RUNTIME_EXPORT void approx_quantile_jit_rt(const int64_t new_set_handle,
459  const int64_t old_set_handle,
460  const void* that_qmd_handle,
461  const void* this_qmd_handle,
462  const int64_t target_logical_idx) {
463  auto* incoming = reinterpret_cast<quantile::TDigest*>(new_set_handle);
464  if (incoming->centroids().capacity()) {
465  auto* accumulator = reinterpret_cast<quantile::TDigest*>(old_set_handle);
466  if (accumulator->centroids().capacity() == 0u) {
467  *accumulator = std::move(*incoming);
468  } else {
469  accumulator->mergeTDigest(*incoming);
470  }
471  }
472 }
473 
474 extern "C" RUNTIME_EXPORT void mode_jit_rt(const int64_t new_set_handle,
475  const int64_t old_set_handle,
476  const void* that_qmd_handle,
477  const void* this_qmd_handle,
478  const int64_t target_logical_idx) {
479  auto* accumulator = reinterpret_cast<AggMode*>(old_set_handle);
480  auto* incoming = reinterpret_cast<AggMode*>(new_set_handle);
481  accumulator->reduce(std::move(*incoming));
482 }
483 
485  int8_t* groups_buffer,
486  const int8_t* key,
487  const uint32_t key_count,
488  const void* this_qmd_handle,
489  const int8_t* that_buff,
490  const uint32_t that_entry_idx,
491  const uint32_t that_entry_count,
492  const uint32_t row_size_bytes,
493  int64_t** buff_out,
494  uint8_t* empty) {
495  const auto& this_qmd = *reinterpret_cast<const QueryMemoryDescriptor*>(this_qmd_handle);
496  const auto gvi =
497  result_set::get_group_value_reduction(reinterpret_cast<int64_t*>(groups_buffer),
498  this_qmd.getEntryCount(),
499  reinterpret_cast<const int64_t*>(key),
500  key_count,
501  this_qmd.getEffectiveKeyWidth(),
502  this_qmd,
503  reinterpret_cast<const int64_t*>(that_buff),
504  that_entry_idx,
505  that_entry_count,
506  row_size_bytes >> 3);
507  *buff_out = gvi.first;
508  *empty = gvi.second;
509 }
510 
511 extern "C" RUNTIME_EXPORT uint8_t check_watchdog_rt(const size_t sample_seed) {
512  if (UNLIKELY(g_enable_dynamic_watchdog && (sample_seed & 0x3F) == 0 &&
513  dynamic_watchdog())) {
514  return true;
515  }
516  return false;
517 }
518 
519 extern "C" uint8_t check_interrupt_rt(const size_t sample_seed) {
520  // this func is called iff we enable runtime query interrupt
521  if (UNLIKELY((sample_seed & 0xFFFF) == 0 && check_interrupt())) {
522  return true;
523  }
524  return false;
525 }
526 
528  const std::vector<TargetInfo>& targets,
529  const std::vector<int64_t>& target_init_vals,
530  const size_t executor_id)
531  : executor_id_(executor_id)
532  , query_mem_desc_(query_mem_desc)
533  , targets_(targets)
534  , target_init_vals_(target_init_vals) {}
535 
536 // The code generated for a reduction between two result set buffers is structured in
537 // several functions and their IR is stored in the 'ReductionCode' structure. At a high
538 // level, the pseudocode is:
539 //
540 // func is_empty_func(row_ptr):
541 // ...
542 //
543 // func reduce_func_baseline(this_ptr, that_ptr):
544 // if is_empty_func(that_ptr):
545 // return
546 // for each target in the row:
547 // reduce target from that_ptr into this_ptr
548 //
549 // func reduce_func_perfect_hash(this_ptr, that_ptr):
550 // if is_empty_func(that_ptr):
551 // return
552 // for each target in the row:
553 // reduce target from that_ptr into this_ptr
554 //
555 // func reduce_func_idx(this_buff, that_buff, that_entry_index):
556 // that_ptr = that_result_set[that_entry_index]
557 // # Retrieval of 'this_ptr' is different between perfect hash and baseline.
558 // this_ptr = this_result_set[that_entry_index]
559 // or
560 // get_row(key(that_row_ptr), this_result_setBuffer)
561 // reduce_func_[baseline|perfect_hash](this_ptr, that_ptr)
562 //
563 // func reduce_loop(this_buff, that_buff, start_entry_index, end_entry_index):
564 // for that_entry_index in [start_entry_index, end_entry_index):
565 // reduce_func_idx(this_buff, that_buff, that_entry_index)
566 
568  const auto hash_type = query_mem_desc_.getQueryDescriptionType();
570  return {};
571  }
572  auto reduction_code = setup_functions_ir(hash_type);
573  isEmpty(reduction_code);
577  reduceOneEntryNoCollisions(reduction_code);
578  reduceOneEntryNoCollisionsIdx(reduction_code);
579  break;
580  }
582  reduceOneEntryBaseline(reduction_code);
583  reduceOneEntryBaselineIdx(reduction_code);
584  break;
585  }
586  default: {
587  LOG(FATAL) << "Unexpected query description type";
588  }
589  }
590  reduceLoop(reduction_code);
591  // For small result sets, avoid native code generation and use the interpreter instead.
594  return reduction_code;
595  }
596  auto executor = Executor::getExecutor(executor_id_);
597  CodeCacheKey key{cacheKey()};
598  std::lock_guard<std::mutex> compilation_lock(executor->compilation_mutex_);
599  const auto compilation_context =
600  QueryEngine::getInstance()->s_code_accessor->get_or_wait(key);
601  if (compilation_context) {
602  reduction_code.func_ptr =
603  reinterpret_cast<ReductionCode::FuncPtr>(compilation_context->get()->func());
604  return reduction_code;
605  }
606  auto cgen_state_ = std::unique_ptr<CgenState>(new CgenState({}, false, executor.get()));
607  auto cgen_state = reduction_code.cgen_state = cgen_state_.get();
608  cgen_state->set_module_shallow_copy(executor->get_rt_module());
609  reduction_code.module = cgen_state->module_;
610 
611  AUTOMATIC_IR_METADATA(cgen_state);
612  auto ir_is_empty = create_llvm_function(reduction_code.ir_is_empty.get(), cgen_state);
613  auto ir_reduce_one_entry =
614  create_llvm_function(reduction_code.ir_reduce_one_entry.get(), cgen_state);
615  auto ir_reduce_one_entry_idx =
616  create_llvm_function(reduction_code.ir_reduce_one_entry_idx.get(), cgen_state);
617  auto ir_reduce_loop =
618  create_llvm_function(reduction_code.ir_reduce_loop.get(), cgen_state);
619  std::unordered_map<const Function*, llvm::Function*> f;
620  f.emplace(reduction_code.ir_is_empty.get(), ir_is_empty);
621  f.emplace(reduction_code.ir_reduce_one_entry.get(), ir_reduce_one_entry);
622  f.emplace(reduction_code.ir_reduce_one_entry_idx.get(), ir_reduce_one_entry_idx);
623  f.emplace(reduction_code.ir_reduce_loop.get(), ir_reduce_loop);
624  translate_function(reduction_code.ir_is_empty.get(), ir_is_empty, reduction_code, f);
626  reduction_code.ir_reduce_one_entry.get(), ir_reduce_one_entry, reduction_code, f);
627  translate_function(reduction_code.ir_reduce_one_entry_idx.get(),
628  ir_reduce_one_entry_idx,
629  reduction_code,
630  f);
632  reduction_code.ir_reduce_loop.get(), ir_reduce_loop, reduction_code, f);
633  reduction_code.llvm_reduce_loop = ir_reduce_loop;
635  reduction_code.cgen_state = nullptr;
637  reduction_code, ir_is_empty, ir_reduce_one_entry, ir_reduce_one_entry_idx, key);
638  return reduction_code;
639 }
640 
641 void ResultSetReductionJIT::isEmpty(const ReductionCode& reduction_code) const {
642  auto ir_is_empty = reduction_code.ir_is_empty.get();
645  Value* key{nullptr};
646  Value* empty_key_val{nullptr};
647  const auto keys_ptr = ir_is_empty->arg(0);
652  CHECK_LT(static_cast<size_t>(query_mem_desc_.getTargetIdxForKey()),
653  target_init_vals_.size());
654  const int64_t target_slot_off = result_set::get_byteoff_of_slot(
656  const auto slot_ptr = ir_is_empty->add<GetElementPtr>(
657  keys_ptr,
658  ir_is_empty->addConstant<ConstantInt>(target_slot_off, Type::Int32),
659  "is_empty_slot_ptr");
660  const auto compact_sz =
662  key = emit_read_int_from_buff(slot_ptr, compact_sz, ir_is_empty);
663  empty_key_val = ir_is_empty->addConstant<ConstantInt>(
665  } else {
667  case 4: {
670  key = emit_load_i32(keys_ptr, ir_is_empty);
671  empty_key_val = ir_is_empty->addConstant<ConstantInt>(EMPTY_KEY_32, Type::Int32);
672  break;
673  }
674  case 8: {
675  key = emit_load_i64(keys_ptr, ir_is_empty);
676  empty_key_val = ir_is_empty->addConstant<ConstantInt>(EMPTY_KEY_64, Type::Int64);
677  break;
678  }
679  default:
680  LOG(FATAL) << "Invalid key width";
681  }
682  }
683  const auto ret =
684  ir_is_empty->add<ICmp>(ICmp::Predicate::EQ, key, empty_key_val, "is_key_empty");
685  ir_is_empty->add<Ret>(ret);
686 }
687 
689  const ReductionCode& reduction_code) const {
690  auto ir_reduce_one_entry = reduction_code.ir_reduce_one_entry.get();
691  const auto this_row_ptr = ir_reduce_one_entry->arg(0);
692  const auto that_row_ptr = ir_reduce_one_entry->arg(1);
693  const auto that_is_empty =
694  ir_reduce_one_entry->add<Call>(reduction_code.ir_is_empty.get(),
695  std::vector<const Value*>{that_row_ptr},
696  "that_is_empty");
697  ir_reduce_one_entry->add<ReturnEarly>(
698  that_is_empty, ir_reduce_one_entry->addConstant<ConstantInt>(0, Type::Int32), "");
699 
700  const auto key_bytes = get_key_bytes_rowwise(query_mem_desc_);
701  if (key_bytes) { // copy the key from right hand side
702  ir_reduce_one_entry->add<MemCpy>(
703  this_row_ptr,
704  that_row_ptr,
705  ir_reduce_one_entry->addConstant<ConstantInt>(key_bytes, Type::Int32));
706  }
707 
708  const auto key_bytes_with_padding = align_to_int64(key_bytes);
709  const auto key_bytes_lv =
710  ir_reduce_one_entry->addConstant<ConstantInt>(key_bytes_with_padding, Type::Int32);
711  const auto this_targets_start_ptr = ir_reduce_one_entry->add<GetElementPtr>(
712  this_row_ptr, key_bytes_lv, "this_targets_start");
713  const auto that_targets_start_ptr = ir_reduce_one_entry->add<GetElementPtr>(
714  that_row_ptr, key_bytes_lv, "that_targets_start");
715 
717  ir_reduce_one_entry, this_targets_start_ptr, that_targets_start_ptr);
718 }
719 
721  Function* ir_reduce_one_entry,
722  Value* this_targets_start_ptr,
723  Value* that_targets_start_ptr) const {
724  const auto& col_slot_context = query_mem_desc_.getColSlotContext();
725  Value* this_targets_ptr = this_targets_start_ptr;
726  Value* that_targets_ptr = that_targets_start_ptr;
727  size_t init_agg_val_idx = 0;
728  for (size_t target_logical_idx = 0; target_logical_idx < targets_.size();
729  ++target_logical_idx) {
730  const auto& target_info = targets_[target_logical_idx];
731  const auto& slots_for_col = col_slot_context.getSlotsForCol(target_logical_idx);
732  Value* this_ptr2{nullptr};
733  Value* that_ptr2{nullptr};
734 
735  bool two_slot_target{false};
736  if (target_info.is_agg &&
737  (target_info.agg_kind == kAVG ||
738  (target_info.agg_kind == kSAMPLE && target_info.sql_type.is_varlen()))) {
739  // Note that this assumes if one of the slot pairs in a given target is an array,
740  // all slot pairs are arrays. Currently this is true for all geo targets, but we
741  // should better codify and store this information in the future
742  two_slot_target = true;
743  }
744 
745  for (size_t target_slot_idx = slots_for_col.front();
746  target_slot_idx < slots_for_col.back() + 1;
747  target_slot_idx += 2) {
748  const auto slot_off_val = query_mem_desc_.getPaddedSlotWidthBytes(target_slot_idx);
749  const auto slot_off =
750  ir_reduce_one_entry->addConstant<ConstantInt>(slot_off_val, Type::Int32);
751  if (UNLIKELY(two_slot_target)) {
752  const auto desc = "target_" + std::to_string(target_logical_idx) + "_second_slot";
753  this_ptr2 = ir_reduce_one_entry->add<GetElementPtr>(
754  this_targets_ptr, slot_off, "this_" + desc);
755  that_ptr2 = ir_reduce_one_entry->add<GetElementPtr>(
756  that_targets_ptr, slot_off, "that_" + desc);
757  }
758  reduceOneSlot(this_targets_ptr,
759  this_ptr2,
760  that_targets_ptr,
761  that_ptr2,
762  target_info,
763  target_logical_idx,
764  target_slot_idx,
765  init_agg_val_idx,
766  slots_for_col.front(),
767  ir_reduce_one_entry);
768  auto increment_agg_val_idx_maybe =
769  [&init_agg_val_idx, &target_logical_idx, this](const int slot_count) {
771  query_mem_desc_.getTargetGroupbyIndex(target_logical_idx) < 0) {
772  init_agg_val_idx += slot_count;
773  }
774  };
775  if (target_logical_idx + 1 == targets_.size() &&
776  target_slot_idx + 1 >= slots_for_col.back()) {
777  break;
778  }
779  const auto next_desc =
780  "target_" + std::to_string(target_logical_idx + 1) + "_first_slot";
781  if (UNLIKELY(two_slot_target)) {
782  increment_agg_val_idx_maybe(2);
783  const auto two_slot_off = ir_reduce_one_entry->addConstant<ConstantInt>(
784  slot_off_val + query_mem_desc_.getPaddedSlotWidthBytes(target_slot_idx + 1),
785  Type::Int32);
786  this_targets_ptr = ir_reduce_one_entry->add<GetElementPtr>(
787  this_targets_ptr, two_slot_off, "this_" + next_desc);
788  that_targets_ptr = ir_reduce_one_entry->add<GetElementPtr>(
789  that_targets_ptr, two_slot_off, "that_" + next_desc);
790  } else {
791  increment_agg_val_idx_maybe(1);
792  this_targets_ptr = ir_reduce_one_entry->add<GetElementPtr>(
793  this_targets_ptr, slot_off, "this_" + next_desc);
794  that_targets_ptr = ir_reduce_one_entry->add<GetElementPtr>(
795  that_targets_ptr, slot_off, "that_" + next_desc);
796  }
797  }
798  }
799  ir_reduce_one_entry->add<Ret>(
800  ir_reduce_one_entry->addConstant<ConstantInt>(0, Type::Int32));
801 }
802 
804  const ReductionCode& reduction_code) const {
805  auto ir_reduce_one_entry = reduction_code.ir_reduce_one_entry.get();
806  const auto this_targets_ptr_arg = ir_reduce_one_entry->arg(0);
807  const auto that_targets_ptr_arg = ir_reduce_one_entry->arg(1);
808  Value* this_ptr1 = this_targets_ptr_arg;
809  Value* that_ptr1 = that_targets_ptr_arg;
810  size_t j = 0;
811  size_t init_agg_val_idx = 0;
812  for (size_t target_logical_idx = 0; target_logical_idx < targets_.size();
813  ++target_logical_idx) {
814  const auto& target_info = targets_[target_logical_idx];
815  Value* this_ptr2{nullptr};
816  Value* that_ptr2{nullptr};
817  if (target_info.is_agg &&
818  (target_info.agg_kind == kAVG ||
819  (target_info.agg_kind == kSAMPLE && target_info.sql_type.is_varlen()))) {
820  const auto desc = "target_" + std::to_string(target_logical_idx) + "_second_slot";
821  const auto second_slot_rel_off =
822  ir_reduce_one_entry->addConstant<ConstantInt>(sizeof(int64_t), Type::Int32);
823  this_ptr2 = ir_reduce_one_entry->add<GetElementPtr>(
824  this_ptr1, second_slot_rel_off, "this_" + desc);
825  that_ptr2 = ir_reduce_one_entry->add<GetElementPtr>(
826  that_ptr1, second_slot_rel_off, "that_" + desc);
827  }
828  reduceOneSlot(this_ptr1,
829  this_ptr2,
830  that_ptr1,
831  that_ptr2,
832  target_info,
833  target_logical_idx,
834  j,
835  init_agg_val_idx,
836  j,
837  ir_reduce_one_entry);
838  if (target_logical_idx + 1 == targets_.size()) {
839  break;
840  }
842  init_agg_val_idx = advance_slot(init_agg_val_idx, target_info, false);
843  } else {
844  if (query_mem_desc_.getTargetGroupbyIndex(target_logical_idx) < 0) {
845  init_agg_val_idx = advance_slot(init_agg_val_idx, target_info, false);
846  }
847  }
848  j = advance_slot(j, target_info, false);
849  const auto next_desc =
850  "target_" + std::to_string(target_logical_idx + 1) + "_first_slot";
851  auto next_slot_rel_off = ir_reduce_one_entry->addConstant<ConstantInt>(
852  init_agg_val_idx * sizeof(int64_t), Type::Int32);
853  this_ptr1 = ir_reduce_one_entry->add<GetElementPtr>(
854  this_targets_ptr_arg, next_slot_rel_off, next_desc);
855  that_ptr1 = ir_reduce_one_entry->add<GetElementPtr>(
856  that_targets_ptr_arg, next_slot_rel_off, next_desc);
857  }
858  ir_reduce_one_entry->add<Ret>(
859  ir_reduce_one_entry->addConstant<ConstantInt>(0, Type::Int32));
860 }
861 
863  const ReductionCode& reduction_code) const {
864  auto ir_reduce_one_entry_idx = reduction_code.ir_reduce_one_entry_idx.get();
869  const auto this_buff = ir_reduce_one_entry_idx->arg(0);
870  const auto that_buff = ir_reduce_one_entry_idx->arg(1);
871  const auto entry_idx = ir_reduce_one_entry_idx->arg(2);
872  const auto this_qmd_handle = ir_reduce_one_entry_idx->arg(4);
873  const auto that_qmd_handle = ir_reduce_one_entry_idx->arg(5);
874  const auto serialized_varlen_buffer_arg = ir_reduce_one_entry_idx->arg(6);
875  const auto row_bytes = ir_reduce_one_entry_idx->addConstant<ConstantInt>(
877  const auto entry_idx_64 = ir_reduce_one_entry_idx->add<Cast>(
878  Cast::CastOp::SExt, entry_idx, Type::Int64, "entry_idx_64");
879  const auto row_off_in_bytes = ir_reduce_one_entry_idx->add<BinaryOperator>(
880  BinaryOperator::BinaryOp::Mul, entry_idx_64, row_bytes, "row_off_in_bytes");
881  const auto this_row_ptr = ir_reduce_one_entry_idx->add<GetElementPtr>(
882  this_buff, row_off_in_bytes, "this_row_ptr");
883  const auto that_row_ptr = ir_reduce_one_entry_idx->add<GetElementPtr>(
884  that_buff, row_off_in_bytes, "that_row_ptr");
885  const auto reduce_rc = ir_reduce_one_entry_idx->add<Call>(
886  reduction_code.ir_reduce_one_entry.get(),
887  std::vector<const Value*>{this_row_ptr,
888  that_row_ptr,
889  this_qmd_handle,
890  that_qmd_handle,
891  serialized_varlen_buffer_arg},
892  "");
893  ir_reduce_one_entry_idx->add<Ret>(reduce_rc);
894 }
895 
897  const ReductionCode& reduction_code) const {
898  auto ir_reduce_one_entry_idx = reduction_code.ir_reduce_one_entry_idx.get();
903  const auto this_buff = ir_reduce_one_entry_idx->arg(0);
904  const auto that_buff = ir_reduce_one_entry_idx->arg(1);
905  const auto that_entry_idx = ir_reduce_one_entry_idx->arg(2);
906  const auto that_entry_count = ir_reduce_one_entry_idx->arg(3);
907  const auto this_qmd_handle = ir_reduce_one_entry_idx->arg(4);
908  const auto that_qmd_handle = ir_reduce_one_entry_idx->arg(5);
909  const auto serialized_varlen_buffer_arg = ir_reduce_one_entry_idx->arg(6);
910  const auto row_bytes = ir_reduce_one_entry_idx->addConstant<ConstantInt>(
912  const auto that_entry_idx_64 = ir_reduce_one_entry_idx->add<Cast>(
913  Cast::CastOp::SExt, that_entry_idx, Type::Int64, "that_entry_idx_64");
914  const auto that_row_off_in_bytes =
915  ir_reduce_one_entry_idx->add<BinaryOperator>(BinaryOperator::BinaryOp::Mul,
916  that_entry_idx_64,
917  row_bytes,
918  "that_row_off_in_bytes");
919  const auto that_row_ptr = ir_reduce_one_entry_idx->add<GetElementPtr>(
920  that_buff, that_row_off_in_bytes, "that_row_ptr");
921  const auto that_is_empty =
922  ir_reduce_one_entry_idx->add<Call>(reduction_code.ir_is_empty.get(),
923  std::vector<const Value*>{that_row_ptr},
924  "that_is_empty");
925  ir_reduce_one_entry_idx->add<ReturnEarly>(
926  that_is_empty,
927  ir_reduce_one_entry_idx->addConstant<ConstantInt>(0, Type::Int32),
928  "");
929  const auto key_count = query_mem_desc_.getGroupbyColCount();
930  const auto one_element =
931  ir_reduce_one_entry_idx->addConstant<ConstantInt>(1, Type::Int32);
932  const auto this_targets_ptr_i64_ptr = ir_reduce_one_entry_idx->add<Alloca>(
933  Type::Int64Ptr, one_element, "this_targets_ptr_out");
934  const auto this_is_empty_ptr =
935  ir_reduce_one_entry_idx->add<Alloca>(Type::Int8, one_element, "this_is_empty_out");
936  ir_reduce_one_entry_idx->add<ExternalCall>(
937  "get_group_value_reduction_rt",
938  Type::Void,
939  std::vector<const Value*>{
940  this_buff,
941  that_row_ptr,
942  ir_reduce_one_entry_idx->addConstant<ConstantInt>(key_count, Type::Int32),
943  this_qmd_handle,
944  that_buff,
945  that_entry_idx,
946  that_entry_count,
947  row_bytes,
948  this_targets_ptr_i64_ptr,
949  this_is_empty_ptr},
950  "");
951  const auto this_targets_ptr_i64 = ir_reduce_one_entry_idx->add<Load>(
952  this_targets_ptr_i64_ptr, "this_targets_ptr_i64");
953  auto this_is_empty =
954  ir_reduce_one_entry_idx->add<Load>(this_is_empty_ptr, "this_is_empty");
955  this_is_empty = ir_reduce_one_entry_idx->add<Cast>(
956  Cast::CastOp::Trunc, this_is_empty, Type::Int1, "this_is_empty_bool");
957  ir_reduce_one_entry_idx->add<ReturnEarly>(
958  this_is_empty,
959  ir_reduce_one_entry_idx->addConstant<ConstantInt>(0, Type::Int32),
960  "");
961  const auto key_qw_count = get_slot_off_quad(query_mem_desc_);
962  const auto this_targets_ptr = ir_reduce_one_entry_idx->add<Cast>(
963  Cast::CastOp::BitCast, this_targets_ptr_i64, Type::Int8Ptr, "this_targets_ptr");
964  const auto key_byte_count = key_qw_count * sizeof(int64_t);
965  const auto key_byte_count_lv =
966  ir_reduce_one_entry_idx->addConstant<ConstantInt>(key_byte_count, Type::Int32);
967  const auto that_targets_ptr = ir_reduce_one_entry_idx->add<GetElementPtr>(
968  that_row_ptr, key_byte_count_lv, "that_targets_ptr");
969  const auto reduce_rc = ir_reduce_one_entry_idx->add<Call>(
970  reduction_code.ir_reduce_one_entry.get(),
971  std::vector<const Value*>{this_targets_ptr,
972  that_targets_ptr,
973  this_qmd_handle,
974  that_qmd_handle,
975  serialized_varlen_buffer_arg},
976  "");
977  ir_reduce_one_entry_idx->add<Ret>(reduce_rc);
978 }
979 
980 namespace {
981 
982 void generate_loop_body(For* for_loop,
983  Function* ir_reduce_loop,
984  Function* ir_reduce_one_entry_idx,
985  Value* this_buff,
986  Value* that_buff,
987  Value* start_index,
988  Value* that_entry_count,
989  Value* this_qmd_handle,
990  Value* that_qmd_handle,
991  Value* serialized_varlen_buffer) {
992  const auto that_entry_idx = for_loop->add<BinaryOperator>(
993  BinaryOperator::BinaryOp::Add, for_loop->iter(), start_index, "that_entry_idx");
994  const auto sample_seed =
995  for_loop->add<Cast>(Cast::CastOp::SExt, that_entry_idx, Type::Int64, "");
997  const auto checker_rt_name =
998  g_enable_dynamic_watchdog ? "check_watchdog_rt" : "check_interrupt_rt";
1000  const auto checker_triggered = for_loop->add<ExternalCall>(
1001  checker_rt_name, Type::Int8, std::vector<const Value*>{sample_seed}, "");
1002  const auto interrupt_triggered_bool =
1003  for_loop->add<ICmp>(ICmp::Predicate::NE,
1004  checker_triggered,
1005  ir_reduce_loop->addConstant<ConstantInt>(0, Type::Int8),
1006  "");
1007  for_loop->add<ReturnEarly>(
1008  interrupt_triggered_bool,
1009  ir_reduce_loop->addConstant<ConstantInt>(error_code, Type::Int32),
1010  "");
1011  }
1012  const auto reduce_rc =
1013  for_loop->add<Call>(ir_reduce_one_entry_idx,
1014  std::vector<const Value*>{this_buff,
1015  that_buff,
1016  that_entry_idx,
1017  that_entry_count,
1018  this_qmd_handle,
1019  that_qmd_handle,
1020  serialized_varlen_buffer},
1021  "");
1022 
1023  auto reduce_rc_bool =
1024  for_loop->add<ICmp>(ICmp::Predicate::NE,
1025  reduce_rc,
1026  ir_reduce_loop->addConstant<ConstantInt>(0, Type::Int32),
1027  "");
1028  for_loop->add<ReturnEarly>(reduce_rc_bool, reduce_rc, "");
1029 }
1030 
1031 } // namespace
1032 
1033 void ResultSetReductionJIT::reduceLoop(const ReductionCode& reduction_code) const {
1034  auto ir_reduce_loop = reduction_code.ir_reduce_loop.get();
1035  const auto this_buff_arg = ir_reduce_loop->arg(0);
1036  const auto that_buff_arg = ir_reduce_loop->arg(1);
1037  const auto start_index_arg = ir_reduce_loop->arg(2);
1038  const auto end_index_arg = ir_reduce_loop->arg(3);
1039  const auto that_entry_count_arg = ir_reduce_loop->arg(4);
1040  const auto this_qmd_handle_arg = ir_reduce_loop->arg(5);
1041  const auto that_qmd_handle_arg = ir_reduce_loop->arg(6);
1042  const auto serialized_varlen_buffer_arg = ir_reduce_loop->arg(7);
1043  For* for_loop =
1044  static_cast<For*>(ir_reduce_loop->add<For>(start_index_arg, end_index_arg, ""));
1045  generate_loop_body(for_loop,
1046  ir_reduce_loop,
1047  reduction_code.ir_reduce_one_entry_idx.get(),
1048  this_buff_arg,
1049  that_buff_arg,
1050  start_index_arg,
1051  that_entry_count_arg,
1052  this_qmd_handle_arg,
1053  that_qmd_handle_arg,
1054  serialized_varlen_buffer_arg);
1055  ir_reduce_loop->add<Ret>(ir_reduce_loop->addConstant<ConstantInt>(0, Type::Int32));
1056 }
1057 
1059  Value* this_ptr2,
1060  Value* that_ptr1,
1061  Value* that_ptr2,
1062  const TargetInfo& target_info,
1063  const size_t target_logical_idx,
1064  const size_t target_slot_idx,
1065  const size_t init_agg_val_idx,
1066  const size_t first_slot_idx_for_target,
1067  Function* ir_reduce_one_entry) const {
1069  if (query_mem_desc_.getTargetGroupbyIndex(target_logical_idx) >= 0) {
1070  return;
1071  }
1072  }
1073  const bool float_argument_input = takes_float_argument(target_info);
1074  const auto chosen_bytes = result_set::get_width_for_slot(
1075  target_slot_idx, float_argument_input, query_mem_desc_);
1076  CHECK_LT(init_agg_val_idx, target_init_vals_.size());
1077  auto init_val = target_init_vals_[init_agg_val_idx];
1078  if (target_info.is_agg &&
1079  (target_info.agg_kind != kSINGLE_VALUE && target_info.agg_kind != kSAMPLE)) {
1080  reduceOneAggregateSlot(this_ptr1,
1081  this_ptr2,
1082  that_ptr1,
1083  that_ptr2,
1084  target_info,
1085  target_logical_idx,
1086  target_slot_idx,
1087  init_val,
1088  chosen_bytes,
1089  ir_reduce_one_entry);
1090  } else if (target_info.agg_kind == kSINGLE_VALUE) {
1091  const auto checked_rc = emit_checked_write_projection(
1092  this_ptr1, that_ptr1, init_val, chosen_bytes, ir_reduce_one_entry);
1093 
1094  auto checked_rc_bool = ir_reduce_one_entry->add<ICmp>(
1096  checked_rc,
1097  ir_reduce_one_entry->addConstant<ConstantInt>(0, Type::Int32),
1098  "");
1099 
1100  ir_reduce_one_entry->add<ReturnEarly>(checked_rc_bool, checked_rc, "");
1101 
1102  } else {
1104  this_ptr1, that_ptr1, init_val, chosen_bytes, ir_reduce_one_entry);
1105  if (target_info.agg_kind == kSAMPLE && target_info.sql_type.is_varlen()) {
1106  CHECK(this_ptr2 && that_ptr2);
1107  size_t length_to_elems{0};
1108  if (target_info.sql_type.is_geometry()) {
1109  // TODO: Assumes hard-coded sizes for geometry targets
1110  length_to_elems = target_slot_idx == first_slot_idx_for_target ? 1 : 4;
1111  } else {
1112  const auto& elem_ti = target_info.sql_type.get_elem_type();
1113  length_to_elems = target_info.sql_type.is_string() ? 1 : elem_ti.get_size();
1114  }
1115  const auto serialized_varlen_buffer_arg = ir_reduce_one_entry->arg(4);
1116  ir_reduce_one_entry->add<ExternalCall>(
1117  "serialized_varlen_buffer_sample",
1118  Type::Void,
1119  std::vector<const Value*>{
1120  serialized_varlen_buffer_arg,
1121  this_ptr1,
1122  this_ptr2,
1123  that_ptr1,
1124  that_ptr2,
1125  ir_reduce_one_entry->addConstant<ConstantInt>(init_val, Type::Int64),
1126  ir_reduce_one_entry->addConstant<ConstantInt>(length_to_elems,
1127  Type::Int64)},
1128  "");
1129  }
1130  }
1131 }
1132 
1134  Value* this_ptr2,
1135  Value* that_ptr1,
1136  Value* that_ptr2,
1137  const TargetInfo& target_info,
1138  const size_t target_logical_idx,
1139  const size_t target_slot_idx,
1140  const int64_t init_val,
1141  const int8_t chosen_bytes,
1142  Function* ir_reduce_one_entry) const {
1143  auto agg_kind = target_info.agg_kind;
1144  switch (agg_kind) {
1145  case kCOUNT:
1146  case kCOUNT_IF:
1148  if (is_distinct_target(target_info)) {
1149  CHECK_EQ(static_cast<size_t>(chosen_bytes), sizeof(int64_t));
1151  this_ptr1, that_ptr1, target_logical_idx, ir_reduce_one_entry);
1152  break;
1153  }
1154  CHECK_EQ(int64_t(0), init_val);
1155  emit_aggregate_one_count(this_ptr1, that_ptr1, chosen_bytes, ir_reduce_one_entry);
1156  break;
1157  case kAPPROX_QUANTILE:
1158  CHECK_EQ(sizeof(int64_t), static_cast<size_t>(chosen_bytes));
1160  this_ptr1, that_ptr1, target_logical_idx, ir_reduce_one_entry);
1161  break;
1162  case kMODE:
1163  reduceOneModeSlot(this_ptr1, that_ptr1, target_logical_idx, ir_reduce_one_entry);
1164  break;
1165  case kAVG:
1166  // Ignore float argument compaction for count component for fear of its overflow
1167  emit_aggregate_one_count(this_ptr2,
1168  that_ptr2,
1169  query_mem_desc_.getPaddedSlotWidthBytes(target_slot_idx),
1170  ir_reduce_one_entry);
1171  agg_kind = kSUM;
1172  // fall thru
1173  case kSUM:
1174  case kMIN:
1175  case kMAX:
1176  // for conditional aggregation, we already "conditionally" aggregate value for each
1177  // resultset, so reduction just can use the non-conditional aggregation logic
1178  case kSUM_IF:
1180  this_ptr1,
1181  that_ptr1,
1182  init_val,
1183  chosen_bytes,
1184  target_info,
1185  ir_reduce_one_entry);
1186  break;
1187  default:
1188  UNREACHABLE() << "Invalid aggregate type: " << agg_kind;
1189  }
1190 }
1191 
1193  Value* this_ptr1,
1194  Value* that_ptr1,
1195  const size_t target_logical_idx,
1196  Function* ir_reduce_one_entry) const {
1198  const auto old_set_handle = emit_load_i64(this_ptr1, ir_reduce_one_entry);
1199  const auto new_set_handle = emit_load_i64(that_ptr1, ir_reduce_one_entry);
1200  const auto this_qmd_arg = ir_reduce_one_entry->arg(2);
1201  const auto that_qmd_arg = ir_reduce_one_entry->arg(3);
1202  ir_reduce_one_entry->add<ExternalCall>(
1203  "count_distinct_set_union_jit_rt",
1204  Type::Void,
1205  std::vector<const Value*>{
1206  new_set_handle,
1207  old_set_handle,
1208  that_qmd_arg,
1209  this_qmd_arg,
1210  ir_reduce_one_entry->addConstant<ConstantInt>(target_logical_idx, Type::Int64)},
1211  "");
1212 }
1213 
1215  Value* this_ptr1,
1216  Value* that_ptr1,
1217  const size_t target_logical_idx,
1218  Function* ir_reduce_one_entry) const {
1220  const auto old_set_handle = emit_load_i64(this_ptr1, ir_reduce_one_entry);
1221  const auto new_set_handle = emit_load_i64(that_ptr1, ir_reduce_one_entry);
1222  const auto this_qmd_arg = ir_reduce_one_entry->arg(2);
1223  const auto that_qmd_arg = ir_reduce_one_entry->arg(3);
1224  ir_reduce_one_entry->add<ExternalCall>(
1225  "approx_quantile_jit_rt",
1226  Type::Void,
1227  std::vector<const Value*>{
1228  new_set_handle,
1229  old_set_handle,
1230  that_qmd_arg,
1231  this_qmd_arg,
1232  ir_reduce_one_entry->addConstant<ConstantInt>(target_logical_idx, Type::Int64)},
1233  "");
1234 }
1235 
1237  Value* that_ptr1,
1238  const size_t target_logical_idx,
1239  Function* ir_reduce_one_entry) const {
1241  const auto old_set_handle = emit_load_i64(this_ptr1, ir_reduce_one_entry);
1242  const auto new_set_handle = emit_load_i64(that_ptr1, ir_reduce_one_entry);
1243  const auto this_qmd_arg = ir_reduce_one_entry->arg(2);
1244  const auto that_qmd_arg = ir_reduce_one_entry->arg(3);
1245  ir_reduce_one_entry->add<ExternalCall>(
1246  "mode_jit_rt",
1247  Type::Void,
1248  std::vector<const Value*>{
1249  new_set_handle,
1250  old_set_handle,
1251  that_qmd_arg,
1252  this_qmd_arg,
1253  ir_reduce_one_entry->addConstant<ConstantInt>(target_logical_idx, Type::Int64)},
1254  "");
1255 }
1256 
1258  ReductionCode& reduction_code,
1259  const llvm::Function* ir_is_empty,
1260  const llvm::Function* ir_reduce_one_entry,
1261  const llvm::Function* ir_reduce_one_entry_idx,
1262  const CodeCacheKey& key) const {
1263  CompilationOptions co{
1265  VLOG(3) << "Reduction Loop:\n"
1266  << serialize_llvm_object(reduction_code.llvm_reduce_loop);
1267  VLOG(3) << "Reduction Is Empty Func:\n" << serialize_llvm_object(ir_is_empty);
1268  VLOG(3) << "Reduction One Entry Func:\n" << serialize_llvm_object(ir_reduce_one_entry);
1269  VLOG(3) << "Reduction One Entry Idx Func:\n"
1270  << serialize_llvm_object(ir_reduce_one_entry_idx);
1271 #ifdef NDEBUG
1272  LOG(IR) << "Reduction Loop:\n"
1273  << serialize_llvm_object(reduction_code.llvm_reduce_loop);
1274  LOG(IR) << "Reduction Is Empty Func:\n" << serialize_llvm_object(ir_is_empty);
1275  LOG(IR) << "Reduction One Entry Func:\n" << serialize_llvm_object(ir_reduce_one_entry);
1276  LOG(IR) << "Reduction One Entry Idx Func:\n"
1277  << serialize_llvm_object(ir_reduce_one_entry_idx);
1278 #else
1279  LOG(IR) << serialize_llvm_object(reduction_code.module);
1280 #endif
1282  reduction_code.llvm_reduce_loop, {reduction_code.llvm_reduce_loop}, co);
1283  auto cpu_compilation_context = std::make_shared<CpuCompilationContext>(std::move(ee));
1284  cpu_compilation_context->setFunctionPointer(reduction_code.llvm_reduce_loop);
1285  reduction_code.func_ptr =
1286  reinterpret_cast<ReductionCode::FuncPtr>(cpu_compilation_context->func());
1287  CHECK(reduction_code.llvm_reduce_loop->getParent() == reduction_code.module);
1288  auto executor = Executor::getExecutor(executor_id_);
1289  QueryEngine::getInstance()->s_code_accessor->reset(key,
1290  std::move(cpu_compilation_context));
1291 }
1292 
1293 namespace {
1294 
1295 std::string target_info_key(const TargetInfo& target_info) {
1296  return std::to_string(target_info.is_agg) + "\n" +
1297  std::to_string(target_info.agg_kind) + "\n" +
1298  target_info.sql_type.get_type_name() + "\n" +
1299  std::to_string(target_info.sql_type.get_notnull()) + "\n" +
1300  target_info.agg_arg_type.get_type_name() + "\n" +
1301  std::to_string(target_info.agg_arg_type.get_notnull()) + "\n" +
1302  std::to_string(target_info.skip_null_val) + "\n" +
1303  std::to_string(target_info.is_distinct);
1304 }
1305 
1306 } // namespace
1307 
1308 std::string ResultSetReductionJIT::cacheKey() const {
1309  std::vector<std::string> target_init_vals_strings;
1311  target_init_vals_.end(),
1312  std::back_inserter(target_init_vals_strings),
1313  [](const int64_t v) { return std::to_string(v); });
1314  const auto target_init_vals_key =
1315  boost::algorithm::join(target_init_vals_strings, ", ");
1316  std::vector<std::string> targets_strings;
1318  targets_.begin(),
1319  targets_.end(),
1320  std::back_inserter(targets_strings),
1321  [](const TargetInfo& target_info) { return target_info_key(target_info); });
1322  const auto targets_key = boost::algorithm::join(targets_strings, ", ");
1323  return query_mem_desc_.reductionKey() + "\n" + target_init_vals_key + "\n" +
1324  targets_key;
1325 }
1326 
1328  const auto hash_type = query_mem_desc_.getQueryDescriptionType();
1329  auto reduction_code = setup_functions_ir(hash_type);
1331  isEmpty(reduction_code);
1332  reduceOneEntryNoCollisions(reduction_code);
1333  reduceOneEntryNoCollisionsIdx(reduction_code);
1334  reduceLoop(reduction_code);
1335  auto executor = Executor::getExecutor(executor_id_);
1336  auto cgen_state_ = std::unique_ptr<CgenState>(new CgenState({}, false, executor.get()));
1337  auto cgen_state = reduction_code.cgen_state = cgen_state_.get();
1338  // CHECK(executor->thread_id_ == logger::thread_id()); // do we need compilation mutex?
1339  cgen_state->set_module_shallow_copy(executor->get_rt_module());
1340  reduction_code.module = cgen_state->module_;
1341 
1342  AUTOMATIC_IR_METADATA(cgen_state);
1343  auto ir_is_empty = create_llvm_function(reduction_code.ir_is_empty.get(), cgen_state);
1344  auto ir_reduce_one_entry =
1345  create_llvm_function(reduction_code.ir_reduce_one_entry.get(), cgen_state);
1346  auto ir_reduce_one_entry_idx =
1347  create_llvm_function(reduction_code.ir_reduce_one_entry_idx.get(), cgen_state);
1348  auto ir_reduce_loop =
1349  create_llvm_function(reduction_code.ir_reduce_loop.get(), cgen_state);
1350  std::unordered_map<const Function*, llvm::Function*> f;
1351  f.emplace(reduction_code.ir_is_empty.get(), ir_is_empty);
1352  f.emplace(reduction_code.ir_reduce_one_entry.get(), ir_reduce_one_entry);
1353  f.emplace(reduction_code.ir_reduce_one_entry_idx.get(), ir_reduce_one_entry_idx);
1354  f.emplace(reduction_code.ir_reduce_loop.get(), ir_reduce_loop);
1355  translate_function(reduction_code.ir_is_empty.get(), ir_is_empty, reduction_code, f);
1357  reduction_code.ir_reduce_one_entry.get(), ir_reduce_one_entry, reduction_code, f);
1358  translate_function(reduction_code.ir_reduce_one_entry_idx.get(),
1359  ir_reduce_one_entry_idx,
1360  reduction_code,
1361  f);
1363  reduction_code.ir_reduce_loop.get(), ir_reduce_loop, reduction_code, f);
1364  reduction_code.llvm_reduce_loop = ir_reduce_loop;
1365  reduction_code.cgen_state = nullptr;
1366  return reduction_code;
1367 }
GroupByPerfectHash
Definition: enums.h:58
GroupValueInfo get_group_value_reduction(int64_t *groups_buffer, const uint32_t groups_buffer_entry_count, const int64_t *key, const uint32_t key_count, const size_t key_width, const QueryMemoryDescriptor &query_mem_desc, const int64_t *that_buff_i64, const size_t that_entry_idx, const size_t that_entry_count, const uint32_t row_size_quad)
std::string to_lower(const std::string &str)
SQLAgg
Definition: sqldefs.h:76
#define CHECK_EQ(x, y)
Definition: Logger.h:301
CgenState * cgen_state
void reduceOneSlot(Value *this_ptr1, Value *this_ptr2, Value *that_ptr1, Value *that_ptr2, const TargetInfo &target_info, const size_t target_logical_idx, const size_t target_slot_idx, const size_t init_agg_val_idx, const size_t first_slot_idx_for_target, Function *ir_reduce_one_entry) const
void reduce(AggMode &&rhs)
Definition: AggMode.h:47
bool is_aggregate_query(const QueryDescriptionType hash_type)
void count_distinct_set_union(const int64_t new_set_handle, const int64_t old_set_handle, const CountDistinctDescriptor &new_count_distinct_desc, const CountDistinctDescriptor &old_count_distinct_desc)
__device__ bool dynamic_watchdog()
#define EMPTY_KEY_64
const std::string & label() const
NonGroupedAggregate
Definition: enums.h:58
RUNTIME_EXPORT uint8_t check_watchdog_rt(const size_t sample_seed)
void reduceOneEntryNoCollisions(const ReductionCode &reduction_code) const
int64_t getTargetGroupbyIndex(const size_t target_idx) const
void varlen_buffer_sample(int8_t *this_ptr1, int8_t *this_ptr2, const int8_t *that_ptr1, const int8_t *that_ptr2, const int64_t init_val)
std::unique_ptr< Function > ir_reduce_loop
Value * emit_read_int_from_buff(Value *ptr, const int8_t compact_sz, Function *function)
void reduceOneEntryBaselineIdx(const ReductionCode &reduction_code) const
SQLTypeInfo sql_type
Definition: TargetInfo.h:52
#define LOG(tag)
Definition: Logger.h:285
void mark_function_always_inline(llvm::Function *func)
Calculate approximate median and general quantiles, based on &quot;Computing Extremely Accurate Quantiles ...
void reduceLoop(const ReductionCode &reduction_code) const
bool is_varlen() const
Definition: sqltypes.h:631
std::string join(T const &container, std::string const &delim)
llvm::Function * llvm_reduce_loop
#define UNREACHABLE()
Definition: Logger.h:338
void reduceOneEntryNoCollisionsIdx(const ReductionCode &reduction_code) const
#define CHECK_GE(x, y)
Definition: Logger.h:306
std::vector< std::string > CodeCacheKey
Definition: CodeCache.h:24
size_t get_slot_off_quad(const QueryMemoryDescriptor &query_mem_desc)
std::string cacheKey() const
size_t getEffectiveKeyWidth() const
std::unique_ptr< Function > ir_reduce_one_entry
bool g_enable_dynamic_watchdog
Definition: Execute.cpp:81
static ExecutionEngineWrapper generateNativeCPUCode(llvm::Function *func, const std::unordered_set< llvm::Function * > &live_funcs, const CompilationOptions &co)
const std::vector< int64_t > target_init_vals_
void reduceOneAggregateSlot(Value *this_ptr1, Value *this_ptr2, Value *that_ptr1, Value *that_ptr2, const TargetInfo &target_info, const size_t target_logical_idx, const size_t target_slot_idx, const int64_t init_val, const int8_t chosen_bytes, Function *ir_reduce_one_entry) const
bool takes_float_argument(const TargetInfo &target_info)
Definition: TargetInfo.h:106
bool g_enable_non_kernel_time_query_interrupt
Definition: Execute.cpp:138
Value * add(Args &&...args)
bool skip_null_val
Definition: TargetInfo.h:54
const Value * emit_checked_write_projection(Value *slot_pi8, Value *other_pi8, const int64_t init_val, const size_t chosen_bytes, Function *ir_reduce_one_entry)
std::unique_ptr< Function > setup_reduce_one_entry_idx(ReductionCode *reduction_code)
int32_t(*)(int8_t *this_buff, const int8_t *that_buff, const int32_t start_entry_index, const int32_t end_entry_index, const int32_t that_entry_count, const void *this_qmd, const void *that_qmd, const void *serialized_varlen_buffer) FuncPtr
const QueryMemoryDescriptor query_mem_desc_
std::unique_ptr< Function > ir_is_empty
std::string to_string(char const *&&v)
SQLTypeInfo agg_arg_type
Definition: TargetInfo.h:53
void translate_function(const Function *function, llvm::Function *llvm_function, const ReductionCode &reduction_code, const std::unordered_map< const Function *, llvm::Function * > &f)
void emit_aggregate_one_value(const std::string &agg_kind, Value *val_ptr, Value *other_ptr, const size_t chosen_bytes, const TargetInfo &agg_info, Function *ir_reduce_one_entry)
RUNTIME_EXPORT void serialized_varlen_buffer_sample(const void *serialized_varlen_buffer_handle, int8_t *this_ptr1, int8_t *this_ptr2, const int8_t *that_ptr1, const int8_t *that_ptr2, const int64_t init_val, const int64_t length_to_elems)
Value * emit_load_i32(Value *ptr, Function *function)
Definition: sqldefs.h:78
static std::shared_ptr< Executor > getExecutor(const ExecutorId id, const std::string &debug_dir="", const std::string &debug_file="", const SystemParameters &system_parameters=SystemParameters())
Definition: Execute.cpp:513
const SQLTypeInfo get_compact_type(const TargetInfo &target)
__device__ bool check_interrupt()
int8_t get_width_for_slot(const size_t target_slot_idx, const bool float_argument_input, const QueryMemoryDescriptor &query_mem_desc)
llvm::Module * module_
Definition: CgenState.h:373
llvm::LLVMContext & context_
Definition: CgenState.h:382
size_t get_byteoff_of_slot(const size_t slot_idx, const QueryMemoryDescriptor &query_mem_desc)
bool is_agg
Definition: TargetInfo.h:50
size_t advance_slot(const size_t j, const TargetInfo &target_info, const bool separate_varlen_storage)
void reduceOneCountDistinctSlot(Value *this_ptr1, Value *that_ptr1, const size_t target_logical_idx, Function *ir_reduce_one_entry) const
uint8_t check_interrupt_rt(const size_t sample_seed)
size_t getGroupbyColCount() const
size_t targetGroupbyIndicesSize() const
void generate_loop_body(For *for_loop, Function *ir_reduce_loop, Function *ir_reduce_one_entry_idx, Value *this_buff, Value *that_buff, Value *start_index, Value *that_entry_count, Value *this_qmd_handle, Value *that_qmd_handle, Value *serialized_varlen_buffer)
void emit_write_projection(Value *slot_pi8, Value *other_pi8, const int64_t init_val, const size_t chosen_bytes, Function *ir_reduce_one_entry)
void emit_aggregate_one_nullable_value(SQLAgg const sql_agg, Value *val_ptr, Value *other_ptr, const int64_t init_val, const size_t chosen_bytes, const TargetInfo &agg_info, Function *ir_reduce_one_entry)
Definition: sqldefs.h:80
ReductionCode codegen() const override
bool is_distinct_target(const TargetInfo &target_info)
Definition: TargetInfo.h:102
std::string target_info_key(const TargetInfo &target_info)
OUTPUT transform(INPUT const &input, FUNC const &func)
Definition: misc.h:329
std::unique_ptr< Function > ir_reduce_one_entry_idx
const int8_t getPaddedSlotWidthBytes(const size_t slot_idx) const
ReductionCode setup_functions_ir(const QueryDescriptionType hash_type)
#define AUTOMATIC_IR_METADATA(CGENSTATE)
std::string toString(const Executor::ExtModuleKinds &kind)
Definition: Execute.h:1703
std::unique_ptr< Function > setup_is_empty_entry(ReductionCode *reduction_code)
SQLAgg agg_kind
Definition: TargetInfo.h:51
size_t getCountDistinctDescriptorsSize() const
void reduceOneEntryTargetsNoCollisions(Function *ir_reduce_one_entry, Value *this_targets_start_ptr, Value *that_targets_start_ptr) const
QueryDescriptionType getQueryDescriptionType() const
#define AUTOMATIC_IR_METADATA_DONE()
#define UNLIKELY(x)
Definition: likely.h:25
void set_module_shallow_copy(const std::unique_ptr< llvm::Module > &module, bool always_clone=false)
Definition: CgenState.cpp:380
#define RUNTIME_EXPORT
llvm::Type * llvm_type(const Type type, llvm::LLVMContext &ctx)
virtual ReductionCode codegen() const
const CountDistinctDescriptor & getCountDistinctDescriptor(const size_t idx) const
RUNTIME_EXPORT void mode_jit_rt(const int64_t new_set_handle, const int64_t old_set_handle, const void *that_qmd_handle, const void *this_qmd_handle, const int64_t target_logical_idx)
llvm::Module * module
#define CHECK_LT(x, y)
Definition: Logger.h:303
std::string serialize_llvm_object(const T *llvm_obj)
size_t get_row_bytes(const QueryMemoryDescriptor &query_mem_desc)
RUNTIME_EXPORT void count_distinct_set_union_jit_rt(const int64_t new_set_handle, const int64_t old_set_handle, const void *that_qmd_handle, const void *this_qmd_handle, const int64_t target_logical_idx)
void finalizeReductionCode(ReductionCode &reduction_code, const llvm::Function *ir_is_empty, const llvm::Function *ir_reduce_one_entry, const llvm::Function *ir_reduce_one_entry_idx, const CodeCacheKey &key) const
Definition: sqldefs.h:81
std::unique_ptr< Function > create_function(const std::string name, const std::vector< Function::NamedArg > &arg_types, const Type ret_type, const bool always_inline)
std::string get_type_name() const
Definition: sqltypes.h:484
torch::Tensor f(torch::Tensor x, torch::Tensor W_target, torch::Tensor b_target)
GroupByBaselineHash
Definition: enums.h:58
const Value * iter() const
RUNTIME_EXPORT void approx_quantile_jit_rt(const int64_t new_set_handle, const int64_t old_set_handle, const void *that_qmd_handle, const void *this_qmd_handle, const int64_t target_logical_idx)
RUNTIME_EXPORT void get_group_value_reduction_rt(int8_t *groups_buffer, const int8_t *key, const uint32_t key_count, const void *this_qmd_handle, const int8_t *that_buff, const uint32_t that_entry_idx, const uint32_t that_entry_count, const uint32_t row_size_bytes, int64_t **buff_out, uint8_t *empty)
std::unique_ptr< Function > setup_reduce_one_entry(ReductionCode *reduction_code, const QueryDescriptionType hash_type)
void isEmpty(const ReductionCode &reduction_code) const
Value * emit_load_i64(Value *ptr, Function *function)
def error_code
Definition: report.py:234
const ColSlotContext & getColSlotContext() const
#define CHECK(condition)
Definition: Logger.h:291
bool is_geometry() const
Definition: sqltypes.h:597
#define EMPTY_KEY_32
void reduceOneEntryBaseline(const ReductionCode &reduction_code) const
static std::shared_ptr< QueryEngine > getInstance()
Definition: QueryEngine.h:89
Value * emit_load(Value *ptr, Type ptr_type, Function *function)
bool is_string() const
Definition: sqltypes.h:561
llvm::Function * create_llvm_function(const Function *function, CgenState *cgen_state)
ResultSetReductionJIT(const QueryMemoryDescriptor &query_mem_desc, const std::vector< TargetInfo > &targets, const std::vector< int64_t > &target_init_vals, const size_t executor_id)
string name
Definition: setup.in.py:72
bool is_distinct
Definition: TargetInfo.h:55
HOST DEVICE bool get_notnull() const
Definition: sqltypes.h:398
void emit_aggregate_one_count(Value *val_ptr, Value *other_ptr, const size_t chosen_bytes, Function *ir_reduce_one_entry)
Definition: sqldefs.h:79
SQLTypeInfo get_elem_type() const
Definition: sqltypes.h:977
Definition: sqldefs.h:77
void reduceOneApproxQuantileSlot(Value *this_ptr1, Value *that_ptr1, const size_t target_logical_idx, Function *ir_reduce_one_entry) const
std::unique_ptr< Function > setup_reduce_loop(ReductionCode *reduction_code)
size_t get_key_bytes_rowwise(const QueryMemoryDescriptor &query_mem_desc)
Definition: sqldefs.h:86
SQLAgg get_non_conditional_agg_type(SQLAgg const agg_type)
Definition: sqldefs.h:320
FORCE_INLINE HOST DEVICE T align_to_int64(T addr)
#define VLOG(n)
Definition: Logger.h:388
std::string reductionKey() const
const Executor * getExecutor() const
void reduceOneModeSlot(Value *this_ptr1, Value *that_ptr1, const size_t target_logical_idx, Function *ir_reduce_one_entry) const
int32_t getTargetIdxForKey() const
const std::vector< TargetInfo > targets_