OmniSciDB  c0231cc57d
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ExtensionsIR.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 "ExtensionFunctions.hpp"
22 
23 #include <tuple>
24 
25 extern std::unique_ptr<llvm::Module> udf_gpu_module;
26 extern std::unique_ptr<llvm::Module> udf_cpu_module;
27 
28 namespace {
29 
30 llvm::StructType* get_buffer_struct_type(CgenState* cgen_state,
31  const std::string& ext_func_name,
32  size_t param_num,
33  llvm::Type* elem_type,
34  bool has_is_null) {
35  CHECK(elem_type);
36  CHECK(elem_type->isPointerTy());
37  llvm::StructType* generated_struct_type =
38  (has_is_null ? llvm::StructType::get(cgen_state->context_,
39  {elem_type,
40  llvm::Type::getInt64Ty(cgen_state->context_),
41  llvm::Type::getInt8Ty(cgen_state->context_)},
42  false)
43  : llvm::StructType::get(
44  cgen_state->context_,
45  {elem_type, llvm::Type::getInt64Ty(cgen_state->context_)},
46  false));
47  llvm::Function* udf_func = cgen_state->module_->getFunction(ext_func_name);
48  if (udf_func) {
49  // Compare expected array struct type with type from the function
50  // definition from the UDF module, but use the type from the
51  // module
52  llvm::FunctionType* udf_func_type = udf_func->getFunctionType();
53  CHECK_LE(param_num, udf_func_type->getNumParams());
54  llvm::Type* param_pointer_type = udf_func_type->getParamType(param_num);
55  CHECK(param_pointer_type->isPointerTy());
56  llvm::Type* param_type = param_pointer_type->getPointerElementType();
57  CHECK(param_type->isStructTy());
58  llvm::StructType* struct_type = llvm::cast<llvm::StructType>(param_type);
59  CHECK_GE(struct_type->getStructNumElements(),
60  generated_struct_type->getStructNumElements())
61  << serialize_llvm_object(struct_type);
62 
63  const auto expected_elems = generated_struct_type->elements();
64  const auto current_elems = struct_type->elements();
65  for (size_t i = 0; i < expected_elems.size(); i++) {
66  CHECK_EQ(expected_elems[i], current_elems[i])
67  << "[" << ::toString(expected_elems[i]) << ", " << ::toString(current_elems[i])
68  << "]";
69  }
70 
71  if (struct_type->isLiteral()) {
72  return struct_type;
73  }
74 
75  llvm::StringRef struct_name = struct_type->getStructName();
76 #if LLVM_VERSION_MAJOR >= 12
77  return struct_type->getTypeByName(cgen_state->context_, struct_name);
78 #else
79  return cgen_state->module_->getTypeByName(struct_name);
80 #endif
81  }
82  return generated_struct_type;
83 }
84 
86  llvm::LLVMContext& ctx) {
87  switch (ext_arg_type) {
88  case ExtArgumentType::Bool: // pass thru to Int8
90  return get_int_type(8, ctx);
92  return get_int_type(16, ctx);
94  return get_int_type(32, ctx);
96  return get_int_type(64, ctx);
98  return llvm::Type::getFloatTy(ctx);
100  return llvm::Type::getDoubleTy(ctx);
124  return llvm::Type::getVoidTy(ctx);
125  default:
126  CHECK(false);
127  }
128  CHECK(false);
129  return nullptr;
130 }
131 
133  CHECK(ll_type);
134  const auto bits = ll_type->getPrimitiveSizeInBits();
135 
136  if (ll_type->isFloatingPointTy()) {
137  switch (bits) {
138  case 32:
139  return SQLTypeInfo(kFLOAT, false);
140  case 64:
141  return SQLTypeInfo(kDOUBLE, false);
142  default:
143  LOG(FATAL) << "Unsupported llvm floating point type: " << bits
144  << ", only 32 and 64 bit floating point is supported.";
145  }
146  } else {
147  switch (bits) {
148  case 1:
149  return SQLTypeInfo(kBOOLEAN, false);
150  case 8:
151  return SQLTypeInfo(kTINYINT, false);
152  case 16:
153  return SQLTypeInfo(kSMALLINT, false);
154  case 32:
155  return SQLTypeInfo(kINT, false);
156  case 64:
157  return SQLTypeInfo(kBIGINT, false);
158  default:
159  LOG(FATAL) << "Unrecognized llvm type for SQL type: "
160  << bits; // TODO let's get the real name here
161  }
162  }
163  UNREACHABLE();
164  return SQLTypeInfo();
165 }
166 
168  llvm::LLVMContext& ctx) {
169  CHECK(ti.is_buffer());
170  if (ti.is_bytes()) {
171  return llvm::Type::getInt8PtrTy(ctx);
172  }
173 
174  const auto& elem_ti = ti.get_elem_type();
175  if (elem_ti.is_fp()) {
176  switch (elem_ti.get_size()) {
177  case 4:
178  return llvm::Type::getFloatPtrTy(ctx);
179  case 8:
180  return llvm::Type::getDoublePtrTy(ctx);
181  }
182  }
183 
184  if (elem_ti.is_boolean()) {
185  return llvm::Type::getInt8PtrTy(ctx);
186  }
187 
188  CHECK(elem_ti.is_integer());
189  switch (elem_ti.get_size()) {
190  case 1:
191  return llvm::Type::getInt8PtrTy(ctx);
192  case 2:
193  return llvm::Type::getInt16PtrTy(ctx);
194  case 4:
195  return llvm::Type::getInt32PtrTy(ctx);
196  case 8:
197  return llvm::Type::getInt64PtrTy(ctx);
198  }
199 
200  UNREACHABLE();
201  return nullptr;
202 }
203 
205  const auto& func_ti = function_oper->get_type_info();
206  for (size_t i = 0; i < function_oper->getArity(); ++i) {
207  const auto arg = function_oper->getArg(i);
208  const auto& arg_ti = arg->get_type_info();
209  if ((func_ti.is_array() && arg_ti.is_array()) ||
210  (func_ti.is_bytes() && arg_ti.is_bytes())) {
211  // If the function returns an array and any of the arguments are arrays, allow NULL
212  // scalars.
213  // TODO: Make this a property of the FunctionOper following `RETURN NULL ON NULL`
214  // semantics.
215  return false;
216  } else if (!arg_ti.get_notnull() && !arg_ti.is_buffer()) {
217  // Nullable geometry args will trigger a null check
218  return true;
219  } else {
220  continue;
221  }
222  }
223  return false;
224 }
225 
226 } // namespace
227 
229  int8_t* buffer) {
230  Executor* exec_ptr = reinterpret_cast<Executor*>(exec);
231  if (buffer != nullptr) {
232  exec_ptr->getRowSetMemoryOwner()->addVarlenBuffer(buffer);
233  }
234 }
235 
237  const Analyzer::FunctionOper* function_oper,
238  const CompilationOptions& co) {
240  ExtensionFunction ext_func_sig = [=]() {
242  try {
243  return bind_function(function_oper, /* is_gpu= */ true);
244  } catch (ExtensionFunctionBindingError& e) {
245  LOG(WARNING) << "codegenFunctionOper[GPU]: " << e.what() << " Redirecting "
246  << function_oper->getName() << " to run on CPU.";
247  throw QueryMustRunOnCpu();
248  }
249  } else {
250  try {
251  return bind_function(function_oper, /* is_gpu= */ false);
252  } catch (ExtensionFunctionBindingError& e) {
253  LOG(WARNING) << "codegenFunctionOper[CPU]: " << e.what();
254  throw;
255  }
256  }
257  }();
258 
259  const auto& ret_ti = function_oper->get_type_info();
260  CHECK(ret_ti.is_integer() || ret_ti.is_fp() || ret_ti.is_boolean() ||
261  ret_ti.is_buffer());
262  if (ret_ti.is_buffer() && co.device_type == ExecutorDeviceType::GPU) {
263  // TODO: This is not necessary for runtime UDFs because RBC does
264  // not generated GPU LLVM IR when the UDF is using Buffer objects.
265  // However, we cannot remove it until C++ UDFs can be defined for
266  // different devices independently.
267  throw QueryMustRunOnCpu();
268  }
269 
270  auto ret_ty = ext_arg_type_to_llvm_type(ext_func_sig.getRet(), cgen_state_->context_);
271  const auto current_bb = cgen_state_->ir_builder_.GetInsertBlock();
272  for (auto it : cgen_state_->ext_call_cache_) {
273  if (*it.foper == *function_oper) {
274  auto inst = llvm::dyn_cast<llvm::Instruction>(it.lv);
275  if (inst && inst->getParent() == current_bb) {
276  return it.lv;
277  }
278  }
279  }
280  std::vector<llvm::Value*> orig_arg_lvs;
281  std::vector<size_t> orig_arg_lvs_index;
282  std::unordered_map<llvm::Value*, llvm::Value*> const_arr_size;
283 
284  for (size_t i = 0; i < function_oper->getArity(); ++i) {
285  orig_arg_lvs_index.push_back(orig_arg_lvs.size());
286  const auto arg = function_oper->getArg(i);
287  const auto arg_cast = dynamic_cast<const Analyzer::UOper*>(arg);
288  const auto arg0 =
289  (arg_cast && arg_cast->get_optype() == kCAST) ? arg_cast->get_operand() : arg;
290  const auto array_expr_arg = dynamic_cast<const Analyzer::ArrayExpr*>(arg0);
291  auto is_local_alloc = array_expr_arg && array_expr_arg->isLocalAlloc();
292  const auto& arg_ti = arg->get_type_info();
293  const auto arg_lvs = codegen(arg, true, co);
294  auto geo_uoper_arg = dynamic_cast<const Analyzer::GeoUOper*>(arg);
295  auto geo_binoper_arg = dynamic_cast<const Analyzer::GeoBinOper*>(arg);
296  auto geo_expr_arg = dynamic_cast<const Analyzer::GeoExpr*>(arg);
297  // TODO(adb / d): Assuming no const array cols for geo (for now)
298  if ((geo_uoper_arg || geo_binoper_arg) && arg_ti.is_geometry()) {
299  // Extract arr sizes and put them in the map, forward arr pointers
300  CHECK_EQ(2 * static_cast<size_t>(arg_ti.get_physical_coord_cols()), arg_lvs.size());
301  for (size_t i = 0; i < arg_lvs.size(); i++) {
302  auto arr = arg_lvs[i++];
303  auto size = arg_lvs[i];
304  orig_arg_lvs.push_back(arr);
305  const_arr_size[arr] = size;
306  }
307  } else if (geo_expr_arg && geo_expr_arg->get_type_info().is_geometry()) {
308  CHECK(geo_expr_arg->get_type_info().get_type() == kPOINT);
309  CHECK_EQ(arg_lvs.size(), size_t(2));
310  for (size_t j = 0; j < arg_lvs.size(); j++) {
311  orig_arg_lvs.push_back(arg_lvs[j]);
312  }
313  } else if (arg_ti.is_geometry()) {
314  CHECK_EQ(static_cast<size_t>(arg_ti.get_physical_coord_cols()), arg_lvs.size());
315  for (size_t j = 0; j < arg_lvs.size(); j++) {
316  orig_arg_lvs.push_back(arg_lvs[j]);
317  }
318  } else if (arg_ti.is_bytes()) {
319  CHECK_EQ(size_t(3), arg_lvs.size());
320  /* arg_lvs contains:
321  c = string_decode(&col_buf0, pos)
322  ptr = extract_str_ptr(c)
323  sz = extract_str_len(c)
324  */
325  for (size_t j = 0; j < arg_lvs.size(); j++) {
326  orig_arg_lvs.push_back(arg_lvs[j]);
327  }
328  } else {
329  if (arg_lvs.size() > 1) {
330  CHECK(arg_ti.is_array());
331  CHECK_EQ(size_t(2), arg_lvs.size());
332  const_arr_size[arg_lvs.front()] = arg_lvs.back();
333  } else {
334  CHECK_EQ(size_t(1), arg_lvs.size());
335  /* arg_lvs contains:
336  &col_buf1
337  */
338  if (is_local_alloc && arg_ti.get_size() > 0) {
339  const_arr_size[arg_lvs.front()] = cgen_state_->llInt(arg_ti.get_size());
340  }
341  }
342  orig_arg_lvs.push_back(arg_lvs.front());
343  }
344  }
345  // The extension function implementations don't handle NULL, they work under
346  // the assumption that the inputs are validated before calling them. Generate
347  // code to do the check at the call site: if any argument is NULL, return NULL
348  // without calling the function at all.
349  const auto [bbs, null_buffer_ptr] = beginArgsNullcheck(function_oper, orig_arg_lvs);
350  CHECK_GE(orig_arg_lvs.size(), function_oper->getArity());
351  // Arguments must be converted to the types the extension function can handle.
353  function_oper, &ext_func_sig, orig_arg_lvs, orig_arg_lvs_index, const_arr_size, co);
354 
355  llvm::Value* buffer_ret{nullptr};
356  if (ret_ti.is_buffer()) {
357  // codegen buffer return as first arg
358  CHECK(ret_ti.is_array() || ret_ti.is_bytes());
359  ret_ty = llvm::Type::getVoidTy(cgen_state_->context_);
360  const auto struct_ty = get_buffer_struct_type(
361  cgen_state_,
362  function_oper->getName(),
363  0,
365  /* has_is_null = */ ret_ti.is_array() || ret_ti.is_bytes());
366  buffer_ret = cgen_state_->ir_builder_.CreateAlloca(struct_ty);
367  args.insert(args.begin(), buffer_ret);
368  }
369 
370  const auto ext_call = cgen_state_->emitExternalCall(
371  ext_func_sig.getName(), ret_ty, args, {}, ret_ti.is_buffer());
372  auto ext_call_nullcheck = endArgsNullcheck(
373  bbs, ret_ti.is_buffer() ? buffer_ret : ext_call, null_buffer_ptr, function_oper);
374 
375  // Cast the return of the extension function to match the FunctionOper
376  if (!(ret_ti.is_buffer())) {
377  const auto extension_ret_ti = get_sql_type_from_llvm_type(ret_ty);
378  if (bbs.args_null_bb &&
379  extension_ret_ti.get_type() != function_oper->get_type_info().get_type() &&
380  // Skip i1-->i8 casts for ST_ functions.
381  // function_oper ret type is i1, extension ret type is 'upgraded' to i8
382  // during type deserialization to 'handle' NULL returns, hence i1-->i8.
383  // ST_ functions can't return NULLs, we just need to check arg nullness
384  // and if any args are NULL then ST_ function is not called
385  function_oper->getName().substr(0, 3) != std::string("ST_")) {
386  ext_call_nullcheck = codegenCast(ext_call_nullcheck,
387  extension_ret_ti,
388  function_oper->get_type_info(),
389  false,
390  co);
391  }
392  }
393 
394  cgen_state_->ext_call_cache_.push_back({function_oper, ext_call_nullcheck});
395  return ext_call_nullcheck;
396 }
397 
398 // Start the control flow needed for a call site check of NULL arguments.
399 std::tuple<CodeGenerator::ArgNullcheckBBs, llvm::Value*>
401  const std::vector<llvm::Value*>& orig_arg_lvs) {
403  llvm::BasicBlock* args_null_bb{nullptr};
404  llvm::BasicBlock* args_notnull_bb{nullptr};
405  llvm::BasicBlock* orig_bb = cgen_state_->ir_builder_.GetInsertBlock();
406  llvm::Value* null_array_alloca{nullptr};
407  // Only generate the check if required (at least one argument must be nullable).
408  if (ext_func_call_requires_nullcheck(function_oper)) {
409  const auto func_ti = function_oper->get_type_info();
410  if (func_ti.is_buffer()) {
411  const auto arr_struct_ty = get_buffer_struct_type(
412  cgen_state_,
413  function_oper->getName(),
414  0,
416  func_ti.is_array() || func_ti.is_bytes());
417  null_array_alloca = cgen_state_->ir_builder_.CreateAlloca(arr_struct_ty);
418  }
419  const auto args_notnull_lv = cgen_state_->ir_builder_.CreateNot(
420  codegenFunctionOperNullArg(function_oper, orig_arg_lvs));
421  args_notnull_bb = llvm::BasicBlock::Create(
422  cgen_state_->context_, "args_notnull", cgen_state_->current_func_);
423  args_null_bb = llvm::BasicBlock::Create(
425  cgen_state_->ir_builder_.CreateCondBr(args_notnull_lv, args_notnull_bb, args_null_bb);
426  cgen_state_->ir_builder_.SetInsertPoint(args_notnull_bb);
427  }
428  return std::make_tuple(
429  CodeGenerator::ArgNullcheckBBs{args_null_bb, args_notnull_bb, orig_bb},
430  null_array_alloca);
431 }
432 
433 // Wrap up the control flow needed for NULL argument handling.
435  const ArgNullcheckBBs& bbs,
436  llvm::Value* fn_ret_lv,
437  llvm::Value* null_array_ptr,
438  const Analyzer::FunctionOper* function_oper) {
440  if (bbs.args_null_bb) {
441  CHECK(bbs.args_notnull_bb);
442  cgen_state_->ir_builder_.CreateBr(bbs.args_null_bb);
443  cgen_state_->ir_builder_.SetInsertPoint(bbs.args_null_bb);
444 
445  llvm::PHINode* ext_call_phi{nullptr};
446  llvm::Value* null_lv{nullptr};
447  const auto func_ti = function_oper->get_type_info();
448  if (!func_ti.is_buffer()) {
449  // The pre-cast SQL equivalent of the type returned by the extension function.
450  const auto extension_ret_ti = get_sql_type_from_llvm_type(fn_ret_lv->getType());
451 
452  ext_call_phi = cgen_state_->ir_builder_.CreatePHI(
453  extension_ret_ti.is_fp()
454  ? get_fp_type(extension_ret_ti.get_size() * 8, cgen_state_->context_)
455  : get_int_type(extension_ret_ti.get_size() * 8, cgen_state_->context_),
456  2);
457 
458  null_lv =
459  extension_ret_ti.is_fp()
460  ? static_cast<llvm::Value*>(cgen_state_->inlineFpNull(extension_ret_ti))
461  : static_cast<llvm::Value*>(cgen_state_->inlineIntNull(extension_ret_ti));
462  } else {
463  const auto arr_struct_ty = get_buffer_struct_type(
464  cgen_state_,
465  function_oper->getName(),
466  0,
468  true);
469  ext_call_phi =
470  cgen_state_->ir_builder_.CreatePHI(llvm::PointerType::get(arr_struct_ty, 0), 2);
471 
472  CHECK(null_array_ptr);
473  const auto arr_null_bool =
474  cgen_state_->ir_builder_.CreateStructGEP(arr_struct_ty, null_array_ptr, 2);
475  cgen_state_->ir_builder_.CreateStore(
476  llvm::ConstantInt::get(get_int_type(8, cgen_state_->context_), 1),
477  arr_null_bool);
478 
479  const auto arr_null_size =
480  cgen_state_->ir_builder_.CreateStructGEP(arr_struct_ty, null_array_ptr, 1);
481  cgen_state_->ir_builder_.CreateStore(
482  llvm::ConstantInt::get(get_int_type(64, cgen_state_->context_), 0),
483  arr_null_size);
484  }
485  ext_call_phi->addIncoming(fn_ret_lv, bbs.args_notnull_bb);
486  ext_call_phi->addIncoming(func_ti.is_buffer() ? null_array_ptr : null_lv,
487  bbs.orig_bb);
488 
489  return ext_call_phi;
490  }
491  return fn_ret_lv;
492 }
493 
494 namespace {
495 
497  const auto& ret_ti = function_oper->get_type_info();
498  if (!ret_ti.is_integer() && !ret_ti.is_fp()) {
499  return true;
500  }
501  for (size_t i = 0; i < function_oper->getArity(); ++i) {
502  const auto arg = function_oper->getArg(i);
503  const auto& arg_ti = arg->get_type_info();
504  if (!arg_ti.is_integer() && !arg_ti.is_fp()) {
505  return true;
506  }
507  }
508  return false;
509 }
510 
511 } // namespace
512 
515  const CompilationOptions& co) {
517  if (call_requires_custom_type_handling(function_oper)) {
518  // Some functions need the return type to be the same as the input type.
519  if (function_oper->getName() == "FLOOR" || function_oper->getName() == "CEIL") {
520  CHECK_EQ(size_t(1), function_oper->getArity());
521  const auto arg = function_oper->getArg(0);
522  const auto& arg_ti = arg->get_type_info();
523  CHECK(arg_ti.is_decimal());
524  const auto arg_lvs = codegen(arg, true, co);
525  CHECK_EQ(size_t(1), arg_lvs.size());
526  const auto arg_lv = arg_lvs.front();
527  CHECK(arg_lv->getType()->isIntegerTy(64));
529  std::tie(bbs, std::ignore) = beginArgsNullcheck(function_oper, {arg_lvs});
530  const std::string func_name =
531  (function_oper->getName() == "FLOOR") ? "decimal_floor" : "decimal_ceil";
532  const auto covar_result_lv = cgen_state_->emitCall(
533  func_name, {arg_lv, cgen_state_->llInt(exp_to_scale(arg_ti.get_scale()))});
534  const auto ret_ti = function_oper->get_type_info();
535  CHECK(ret_ti.is_decimal());
536  CHECK_EQ(0, ret_ti.get_scale());
537  const auto result_lv = cgen_state_->ir_builder_.CreateSDiv(
538  covar_result_lv, cgen_state_->llInt(exp_to_scale(arg_ti.get_scale())));
539  return endArgsNullcheck(bbs, result_lv, nullptr, function_oper);
540  } else if (function_oper->getName() == "ROUND" &&
541  function_oper->getArg(0)->get_type_info().is_decimal()) {
542  CHECK_EQ(size_t(2), function_oper->getArity());
543 
544  const auto arg0 = function_oper->getArg(0);
545  const auto& arg0_ti = arg0->get_type_info();
546  const auto arg0_lvs = codegen(arg0, true, co);
547  CHECK_EQ(size_t(1), arg0_lvs.size());
548  const auto arg0_lv = arg0_lvs.front();
549  CHECK(arg0_lv->getType()->isIntegerTy(64));
550 
551  const auto arg1 = function_oper->getArg(1);
552  const auto& arg1_ti = arg1->get_type_info();
553  CHECK(arg1_ti.is_integer());
554  const auto arg1_lvs = codegen(arg1, true, co);
555  auto arg1_lv = arg1_lvs.front();
556  if (arg1_ti.get_type() != kINT) {
557  arg1_lv = codegenCast(arg1_lv, arg1_ti, SQLTypeInfo(kINT, true), false, co);
558  }
559 
561  std::tie(bbs0, std::ignore) =
562  beginArgsNullcheck(function_oper, {arg0_lv, arg1_lvs.front()});
563 
564  const std::string func_name = "Round__4";
565  const auto ret_ti = function_oper->get_type_info();
566  CHECK(ret_ti.is_decimal());
567  const auto result_lv = cgen_state_->emitExternalCall(
568  func_name,
570  {arg0_lv, arg1_lv, cgen_state_->llInt(arg0_ti.get_scale())});
571 
572  return endArgsNullcheck(bbs0, result_lv, nullptr, function_oper);
573  }
574  throw std::runtime_error("Type combination not supported for function " +
575  function_oper->getName());
576  }
577  return codegenFunctionOper(function_oper, co);
578 }
579 
580 // Generates code which returns true iff at least one of the arguments is NULL.
582  const Analyzer::FunctionOper* function_oper,
583  const std::vector<llvm::Value*>& orig_arg_lvs) {
585  llvm::Value* one_arg_null =
586  llvm::ConstantInt::get(llvm::IntegerType::getInt1Ty(cgen_state_->context_), false);
587  size_t physical_coord_cols = 0;
588  for (size_t i = 0, j = 0; i < function_oper->getArity();
589  ++i, j += std::max(size_t(1), physical_coord_cols)) {
590  const auto arg = function_oper->getArg(i);
591  const auto& arg_ti = arg->get_type_info();
592  physical_coord_cols = arg_ti.get_physical_coord_cols();
593  if (arg_ti.get_notnull()) {
594  continue;
595  }
596  auto geo_expr_arg = dynamic_cast<const Analyzer::GeoExpr*>(arg);
597  if (geo_expr_arg && arg_ti.is_geometry()) {
598  CHECK(arg_ti.get_type() == kPOINT);
599  auto is_null_lv = cgen_state_->ir_builder_.CreateICmp(
600  llvm::CmpInst::ICMP_EQ,
601  orig_arg_lvs[j],
602  llvm::ConstantPointerNull::get( // TODO: centralize logic; in geo expr?
603  arg_ti.get_compression() == kENCODING_GEOINT
604  ? llvm::Type::getInt32PtrTy(cgen_state_->context_)
605  : llvm::Type::getDoublePtrTy(cgen_state_->context_)));
606  one_arg_null = cgen_state_->ir_builder_.CreateOr(one_arg_null, is_null_lv);
607  physical_coord_cols = 2; // number of lvs to advance
608  continue;
609  }
610 #ifdef ENABLE_GEOS
611  // If geo arg is coming from geos, skip the null check, assume it's a valid geo
612  if (arg_ti.is_geometry()) {
613  auto* coords_load = llvm::dyn_cast<llvm::LoadInst>(orig_arg_lvs[i]);
614  if (coords_load) {
615  continue;
616  }
617  }
618 #endif
619  if (arg_ti.is_geometry()) {
620  auto* coords_alloca = llvm::dyn_cast<llvm::AllocaInst>(orig_arg_lvs[j]);
621  auto* coords_phi = llvm::dyn_cast<llvm::PHINode>(orig_arg_lvs[j]);
622  if (coords_alloca || coords_phi) {
623  // TODO: null check dynamically generated geometries
624  continue;
625  }
626  }
627  if (arg_ti.is_buffer() || arg_ti.is_geometry()) {
628  // POINT [un]compressed coord check requires custom checker and chunk iterator
629  // Non-POINT NULL geographies will have a normally encoded null coord array
630  auto fname =
631  (arg_ti.get_type() == kPOINT) ? "point_coord_array_is_null" : "array_is_null";
632  auto is_null_lv = cgen_state_->emitExternalCall(
633  fname, get_int_type(1, cgen_state_->context_), {orig_arg_lvs[j], posArg(arg)});
634  one_arg_null = cgen_state_->ir_builder_.CreateOr(one_arg_null, is_null_lv);
635  continue;
636  }
637  CHECK(arg_ti.is_number() or arg_ti.is_boolean());
638  one_arg_null = cgen_state_->ir_builder_.CreateOr(
639  one_arg_null, codegenIsNullNumber(orig_arg_lvs[j], arg_ti));
640  }
641  return one_arg_null;
642 }
643 
644 llvm::Value* CodeGenerator::codegenCompression(const SQLTypeInfo& type_info) {
646  int32_t compression = (type_info.get_compression() == kENCODING_GEOINT &&
647  type_info.get_comp_param() == 32)
648  ? 1
649  : 0;
650 
651  return cgen_state_->llInt(compression);
652 }
653 
654 std::pair<llvm::Value*, llvm::Value*> CodeGenerator::codegenArrayBuff(
655  llvm::Value* chunk,
656  llvm::Value* row_pos,
657  SQLTypes array_type,
658  bool cast_and_extend) {
660  const auto elem_ti =
661  SQLTypeInfo(
662  SQLTypes::kARRAY, 0, 0, false, EncodingType::kENCODING_NONE, 0, array_type)
663  .get_elem_type();
664 
665  auto buff = cgen_state_->emitExternalCall(
666  "array_buff", llvm::Type::getInt32PtrTy(cgen_state_->context_), {chunk, row_pos});
667 
668  auto len = cgen_state_->emitExternalCall(
669  "array_size",
670  get_int_type(32, cgen_state_->context_),
671  {chunk, row_pos, cgen_state_->llInt(log2_bytes(elem_ti.get_logical_size()))});
672 
673  if (cast_and_extend) {
674  buff = castArrayPointer(buff, elem_ti);
675  len =
676  cgen_state_->ir_builder_.CreateZExt(len, get_int_type(64, cgen_state_->context_));
677  }
678 
679  return std::make_pair(buff, len);
680 }
681 
682 void CodeGenerator::codegenBufferArgs(const std::string& ext_func_name,
683  size_t param_num,
684  llvm::Value* buffer_buf,
685  llvm::Value* buffer_size,
686  llvm::Value* buffer_null,
687  std::vector<llvm::Value*>& output_args) {
689  CHECK(buffer_buf);
690  CHECK(buffer_size);
691 
692  auto buffer_abstraction = get_buffer_struct_type(
693  cgen_state_, ext_func_name, param_num, buffer_buf->getType(), !!(buffer_null));
694  auto alloc_mem = cgen_state_->ir_builder_.CreateAlloca(buffer_abstraction);
695 
696  auto buffer_buf_ptr =
697  cgen_state_->ir_builder_.CreateStructGEP(buffer_abstraction, alloc_mem, 0);
698  cgen_state_->ir_builder_.CreateStore(buffer_buf, buffer_buf_ptr);
699 
700  auto buffer_size_ptr =
701  cgen_state_->ir_builder_.CreateStructGEP(buffer_abstraction, alloc_mem, 1);
702  cgen_state_->ir_builder_.CreateStore(buffer_size, buffer_size_ptr);
703 
704  if (buffer_null) {
705  auto bool_extended_type = llvm::Type::getInt8Ty(cgen_state_->context_);
706  auto buffer_null_extended =
707  cgen_state_->ir_builder_.CreateZExt(buffer_null, bool_extended_type);
708  auto buffer_is_null_ptr =
709  cgen_state_->ir_builder_.CreateStructGEP(buffer_abstraction, alloc_mem, 2);
710  cgen_state_->ir_builder_.CreateStore(buffer_null_extended, buffer_is_null_ptr);
711  }
712  output_args.push_back(alloc_mem);
713 }
714 
715 llvm::StructType* CodeGenerator::createPointStructType(const std::string& udf_func_name,
716  size_t param_num) {
717  llvm::Module* module_for_lookup = cgen_state_->module_;
718  llvm::Function* udf_func = module_for_lookup->getFunction(udf_func_name);
719 
720  llvm::StructType* generated_struct_type =
721  llvm::StructType::get(cgen_state_->context_,
722  {llvm::Type::getInt8PtrTy(cgen_state_->context_),
723  llvm::Type::getInt32Ty(cgen_state_->context_),
724  llvm::Type::getInt32Ty(cgen_state_->context_),
725  llvm::Type::getInt32Ty(cgen_state_->context_),
726  llvm::Type::getInt32Ty(cgen_state_->context_)},
727  false);
728 
729  if (udf_func) {
730  llvm::FunctionType* udf_func_type = udf_func->getFunctionType();
731  CHECK(param_num < udf_func_type->getNumParams());
732  llvm::Type* param_pointer_type = udf_func_type->getParamType(param_num);
733  CHECK(param_pointer_type->isPointerTy());
734  llvm::Type* param_type = param_pointer_type->getPointerElementType();
735  CHECK(param_type->isStructTy());
736  llvm::StructType* struct_type = llvm::cast<llvm::StructType>(param_type);
737  CHECK_EQ(struct_type->getStructNumElements(), 5u)
738  << serialize_llvm_object(struct_type);
739  const auto expected_elems = generated_struct_type->elements();
740  const auto current_elems = struct_type->elements();
741  for (size_t i = 0; i < expected_elems.size(); i++) {
742  CHECK_EQ(expected_elems[i], current_elems[i]);
743  }
744  if (struct_type->isLiteral()) {
745  return struct_type;
746  }
747 
748  llvm::StringRef struct_name = struct_type->getStructName();
749 #if LLVM_VERSION_MAJOR >= 12
750  llvm::StructType* point_type =
751  struct_type->getTypeByName(cgen_state_->context_, struct_name);
752 #else
753  llvm::StructType* point_type = module_for_lookup->getTypeByName(struct_name);
754 #endif
755  CHECK(point_type);
756 
757  return point_type;
758  }
759  return generated_struct_type;
760 }
761 
762 void CodeGenerator::codegenGeoPointArgs(const std::string& udf_func_name,
763  size_t param_num,
764  llvm::Value* point_buf,
765  llvm::Value* point_size,
766  llvm::Value* compression,
767  llvm::Value* input_srid,
768  llvm::Value* output_srid,
769  std::vector<llvm::Value*>& output_args) {
771  CHECK(point_buf);
772  CHECK(point_size);
773  CHECK(compression);
774  CHECK(input_srid);
775  CHECK(output_srid);
776 
777  auto point_abstraction = createPointStructType(udf_func_name, param_num);
778  auto alloc_mem = cgen_state_->ir_builder_.CreateAlloca(point_abstraction, nullptr);
779 
780  auto point_buf_ptr =
781  cgen_state_->ir_builder_.CreateStructGEP(point_abstraction, alloc_mem, 0);
782  cgen_state_->ir_builder_.CreateStore(point_buf, point_buf_ptr);
783 
784  auto point_size_ptr =
785  cgen_state_->ir_builder_.CreateStructGEP(point_abstraction, alloc_mem, 1);
786  cgen_state_->ir_builder_.CreateStore(point_size, point_size_ptr);
787 
788  auto point_compression_ptr =
789  cgen_state_->ir_builder_.CreateStructGEP(point_abstraction, alloc_mem, 2);
790  cgen_state_->ir_builder_.CreateStore(compression, point_compression_ptr);
791 
792  auto input_srid_ptr =
793  cgen_state_->ir_builder_.CreateStructGEP(point_abstraction, alloc_mem, 3);
794  cgen_state_->ir_builder_.CreateStore(input_srid, input_srid_ptr);
795 
796  auto output_srid_ptr =
797  cgen_state_->ir_builder_.CreateStructGEP(point_abstraction, alloc_mem, 4);
798  cgen_state_->ir_builder_.CreateStore(output_srid, output_srid_ptr);
799 
800  output_args.push_back(alloc_mem);
801 }
802 
804  const std::string& udf_func_name,
805  size_t param_num) {
806  llvm::Module* module_for_lookup = cgen_state_->module_;
807  llvm::Function* udf_func = module_for_lookup->getFunction(udf_func_name);
808 
809  llvm::StructType* generated_struct_type =
810  llvm::StructType::get(cgen_state_->context_,
811  {llvm::Type::getInt8PtrTy(cgen_state_->context_),
812  llvm::Type::getInt32Ty(cgen_state_->context_),
813  llvm::Type::getInt32Ty(cgen_state_->context_),
814  llvm::Type::getInt32Ty(cgen_state_->context_),
815  llvm::Type::getInt32Ty(cgen_state_->context_)},
816  false);
817 
818  if (udf_func) {
819  llvm::FunctionType* udf_func_type = udf_func->getFunctionType();
820  CHECK(param_num < udf_func_type->getNumParams());
821  llvm::Type* param_pointer_type = udf_func_type->getParamType(param_num);
822  CHECK(param_pointer_type->isPointerTy());
823  llvm::Type* param_type = param_pointer_type->getPointerElementType();
824  CHECK(param_type->isStructTy());
825  llvm::StructType* struct_type = llvm::cast<llvm::StructType>(param_type);
826  CHECK(struct_type->isStructTy());
827  CHECK_EQ(struct_type->getStructNumElements(), 5u);
828 
829  const auto expected_elems = generated_struct_type->elements();
830  const auto current_elems = struct_type->elements();
831  for (size_t i = 0; i < expected_elems.size(); i++) {
832  CHECK_EQ(expected_elems[i], current_elems[i]);
833  }
834  if (struct_type->isLiteral()) {
835  return struct_type;
836  }
837 
838  llvm::StringRef struct_name = struct_type->getStructName();
839 #if LLVM_VERSION_MAJOR >= 12
840  llvm::StructType* multi_point_type =
841  struct_type->getTypeByName(cgen_state_->context_, struct_name);
842 #else
843  llvm::StructType* multi_point_type = module_for_lookup->getTypeByName(struct_name);
844 #endif
845  CHECK(multi_point_type);
846 
847  return multi_point_type;
848  }
849  return generated_struct_type;
850 }
851 
852 void CodeGenerator::codegenGeoMultiPointArgs(const std::string& udf_func_name,
853  size_t param_num,
854  llvm::Value* multi_point_buf,
855  llvm::Value* multi_point_size,
856  llvm::Value* compression,
857  llvm::Value* input_srid,
858  llvm::Value* output_srid,
859  std::vector<llvm::Value*>& output_args) {
861  CHECK(multi_point_buf);
862  CHECK(multi_point_size);
863  CHECK(compression);
864  CHECK(input_srid);
865  CHECK(output_srid);
866 
867  auto multi_point_abstraction = createMultiPointStructType(udf_func_name, param_num);
868  auto alloc_mem =
869  cgen_state_->ir_builder_.CreateAlloca(multi_point_abstraction, nullptr);
870 
871  auto multi_point_buf_ptr =
872  cgen_state_->ir_builder_.CreateStructGEP(multi_point_abstraction, alloc_mem, 0);
873  cgen_state_->ir_builder_.CreateStore(multi_point_buf, multi_point_buf_ptr);
874 
875  auto multi_point_size_ptr =
876  cgen_state_->ir_builder_.CreateStructGEP(multi_point_abstraction, alloc_mem, 1);
877  cgen_state_->ir_builder_.CreateStore(multi_point_size, multi_point_size_ptr);
878 
879  auto compression_ptr =
880  cgen_state_->ir_builder_.CreateStructGEP(multi_point_abstraction, alloc_mem, 2);
881  cgen_state_->ir_builder_.CreateStore(compression, compression_ptr);
882 
883  auto input_srid_ptr =
884  cgen_state_->ir_builder_.CreateStructGEP(multi_point_abstraction, alloc_mem, 3);
885  cgen_state_->ir_builder_.CreateStore(input_srid, input_srid_ptr);
886 
887  auto output_srid_ptr =
888  cgen_state_->ir_builder_.CreateStructGEP(multi_point_abstraction, alloc_mem, 4);
889  cgen_state_->ir_builder_.CreateStore(output_srid, output_srid_ptr);
890 
891  output_args.push_back(alloc_mem);
892 }
893 
895  const std::string& udf_func_name,
896  size_t param_num) {
897  llvm::Module* module_for_lookup = cgen_state_->module_;
898  llvm::Function* udf_func = module_for_lookup->getFunction(udf_func_name);
899 
900  llvm::StructType* generated_struct_type =
901  llvm::StructType::get(cgen_state_->context_,
902  {llvm::Type::getInt8PtrTy(cgen_state_->context_),
903  llvm::Type::getInt32Ty(cgen_state_->context_),
904  llvm::Type::getInt32Ty(cgen_state_->context_),
905  llvm::Type::getInt32Ty(cgen_state_->context_),
906  llvm::Type::getInt32Ty(cgen_state_->context_)},
907  false);
908 
909  if (udf_func) {
910  llvm::FunctionType* udf_func_type = udf_func->getFunctionType();
911  CHECK(param_num < udf_func_type->getNumParams());
912  llvm::Type* param_pointer_type = udf_func_type->getParamType(param_num);
913  CHECK(param_pointer_type->isPointerTy());
914  llvm::Type* param_type = param_pointer_type->getPointerElementType();
915  CHECK(param_type->isStructTy());
916  llvm::StructType* struct_type = llvm::cast<llvm::StructType>(param_type);
917  CHECK(struct_type->isStructTy());
918  CHECK_EQ(struct_type->getStructNumElements(), 5u);
919 
920  const auto expected_elems = generated_struct_type->elements();
921  const auto current_elems = struct_type->elements();
922  for (size_t i = 0; i < expected_elems.size(); i++) {
923  CHECK_EQ(expected_elems[i], current_elems[i]);
924  }
925  if (struct_type->isLiteral()) {
926  return struct_type;
927  }
928 
929  llvm::StringRef struct_name = struct_type->getStructName();
930 #if LLVM_VERSION_MAJOR >= 12
931  llvm::StructType* line_string_type =
932  struct_type->getTypeByName(cgen_state_->context_, struct_name);
933 #else
934  llvm::StructType* line_string_type = module_for_lookup->getTypeByName(struct_name);
935 #endif
936  CHECK(line_string_type);
937 
938  return line_string_type;
939  }
940  return generated_struct_type;
941 }
942 
943 void CodeGenerator::codegenGeoLineStringArgs(const std::string& udf_func_name,
944  size_t param_num,
945  llvm::Value* line_string_buf,
946  llvm::Value* line_string_size,
947  llvm::Value* compression,
948  llvm::Value* input_srid,
949  llvm::Value* output_srid,
950  std::vector<llvm::Value*>& output_args) {
952  CHECK(line_string_buf);
953  CHECK(line_string_size);
954  CHECK(compression);
955  CHECK(input_srid);
956  CHECK(output_srid);
957 
958  auto line_string_abstraction = createLineStringStructType(udf_func_name, param_num);
959  auto alloc_mem =
960  cgen_state_->ir_builder_.CreateAlloca(line_string_abstraction, nullptr);
961 
962  auto line_string_buf_ptr =
963  cgen_state_->ir_builder_.CreateStructGEP(line_string_abstraction, alloc_mem, 0);
964  cgen_state_->ir_builder_.CreateStore(line_string_buf, line_string_buf_ptr);
965 
966  auto line_string_size_ptr =
967  cgen_state_->ir_builder_.CreateStructGEP(line_string_abstraction, alloc_mem, 1);
968  cgen_state_->ir_builder_.CreateStore(line_string_size, line_string_size_ptr);
969 
970  auto line_string_compression_ptr =
971  cgen_state_->ir_builder_.CreateStructGEP(line_string_abstraction, alloc_mem, 2);
972  cgen_state_->ir_builder_.CreateStore(compression, line_string_compression_ptr);
973 
974  auto input_srid_ptr =
975  cgen_state_->ir_builder_.CreateStructGEP(line_string_abstraction, alloc_mem, 3);
976  cgen_state_->ir_builder_.CreateStore(input_srid, input_srid_ptr);
977 
978  auto output_srid_ptr =
979  cgen_state_->ir_builder_.CreateStructGEP(line_string_abstraction, alloc_mem, 4);
980  cgen_state_->ir_builder_.CreateStore(output_srid, output_srid_ptr);
981 
982  output_args.push_back(alloc_mem);
983 }
984 
986  const std::string& udf_func_name,
987  size_t param_num) {
988  llvm::Module* module_for_lookup = cgen_state_->module_;
989  llvm::Function* udf_func = module_for_lookup->getFunction(udf_func_name);
990 
991  llvm::StructType* generated_struct_type =
992  llvm::StructType::get(cgen_state_->context_,
993  {llvm::Type::getInt8PtrTy(cgen_state_->context_),
994  llvm::Type::getInt32Ty(cgen_state_->context_),
995  llvm::Type::getInt8PtrTy(cgen_state_->context_),
996  llvm::Type::getInt32Ty(cgen_state_->context_),
997  llvm::Type::getInt32Ty(cgen_state_->context_),
998  llvm::Type::getInt32Ty(cgen_state_->context_),
999  llvm::Type::getInt32Ty(cgen_state_->context_)},
1000  false);
1001 
1002  if (udf_func) {
1003  llvm::FunctionType* udf_func_type = udf_func->getFunctionType();
1004  CHECK(param_num < udf_func_type->getNumParams());
1005  llvm::Type* param_pointer_type = udf_func_type->getParamType(param_num);
1006  CHECK(param_pointer_type->isPointerTy());
1007  llvm::Type* param_type = param_pointer_type->getPointerElementType();
1008  CHECK(param_type->isStructTy());
1009  llvm::StructType* struct_type = llvm::cast<llvm::StructType>(param_type);
1010  CHECK(struct_type->isStructTy());
1011  CHECK_EQ(struct_type->getStructNumElements(), 7u);
1012 
1013  const auto expected_elems = generated_struct_type->elements();
1014  const auto current_elems = struct_type->elements();
1015  for (size_t i = 0; i < expected_elems.size(); i++) {
1016  CHECK_EQ(expected_elems[i], current_elems[i]);
1017  }
1018  if (struct_type->isLiteral()) {
1019  return struct_type;
1020  }
1021 
1022  llvm::StringRef struct_name = struct_type->getStructName();
1023 #if LLVM_VERSION_MAJOR >= 12
1024  llvm::StructType* multi_linestring_type =
1025  struct_type->getTypeByName(cgen_state_->context_, struct_name);
1026 #else
1027  llvm::StructType* multi_linestring_type =
1028  module_for_lookup->getTypeByName(struct_name);
1029 #endif
1030  CHECK(multi_linestring_type);
1031 
1032  return multi_linestring_type;
1033  }
1034  return generated_struct_type;
1035 }
1036 
1038  const std::string& udf_func_name,
1039  size_t param_num,
1040  llvm::Value* multi_linestring_coords,
1041  llvm::Value* multi_linestring_coords_size,
1042  llvm::Value* linestring_sizes,
1043  llvm::Value* linestring_sizes_size,
1044  llvm::Value* compression,
1045  llvm::Value* input_srid,
1046  llvm::Value* output_srid,
1047  std::vector<llvm::Value*>& output_args) {
1049  CHECK(multi_linestring_coords);
1050  CHECK(multi_linestring_coords_size);
1051  CHECK(linestring_sizes);
1052  CHECK(linestring_sizes_size);
1053  CHECK(compression);
1054  CHECK(input_srid);
1055  CHECK(output_srid);
1056 
1057  auto multi_linestring_abstraction =
1058  createMultiLineStringStructType(udf_func_name, param_num);
1059  auto alloc_mem =
1060  cgen_state_->ir_builder_.CreateAlloca(multi_linestring_abstraction, nullptr);
1061 
1062  auto multi_linestring_coords_ptr = cgen_state_->ir_builder_.CreateStructGEP(
1063  multi_linestring_abstraction, alloc_mem, 0);
1064  cgen_state_->ir_builder_.CreateStore(multi_linestring_coords,
1065  multi_linestring_coords_ptr);
1066 
1067  auto multi_linestring_coords_size_ptr = cgen_state_->ir_builder_.CreateStructGEP(
1068  multi_linestring_abstraction, alloc_mem, 1);
1069  cgen_state_->ir_builder_.CreateStore(multi_linestring_coords_size,
1070  multi_linestring_coords_size_ptr);
1071 
1072  auto linestring_sizes_ptr = cgen_state_->ir_builder_.CreateStructGEP(
1073  multi_linestring_abstraction, alloc_mem, 2);
1074  const auto linestring_sizes_ptr_ty =
1075  llvm::dyn_cast<llvm::PointerType>(linestring_sizes_ptr->getType());
1076  CHECK(linestring_sizes_ptr_ty);
1077  cgen_state_->ir_builder_.CreateStore(
1078  cgen_state_->ir_builder_.CreateBitCast(
1079  linestring_sizes, linestring_sizes_ptr_ty->getPointerElementType()),
1080  linestring_sizes_ptr);
1081 
1082  auto linestring_sizes_size_ptr = cgen_state_->ir_builder_.CreateStructGEP(
1083  multi_linestring_abstraction, alloc_mem, 3);
1084  cgen_state_->ir_builder_.CreateStore(linestring_sizes_size, linestring_sizes_size_ptr);
1085 
1086  auto multi_linestring_compression_ptr = cgen_state_->ir_builder_.CreateStructGEP(
1087  multi_linestring_abstraction, alloc_mem, 4);
1088  cgen_state_->ir_builder_.CreateStore(compression, multi_linestring_compression_ptr);
1089 
1090  auto input_srid_ptr = cgen_state_->ir_builder_.CreateStructGEP(
1091  multi_linestring_abstraction, alloc_mem, 5);
1092  cgen_state_->ir_builder_.CreateStore(input_srid, input_srid_ptr);
1093 
1094  auto output_srid_ptr = cgen_state_->ir_builder_.CreateStructGEP(
1095  multi_linestring_abstraction, alloc_mem, 6);
1096  cgen_state_->ir_builder_.CreateStore(output_srid, output_srid_ptr);
1097 
1098  output_args.push_back(alloc_mem);
1099 }
1100 
1101 llvm::StructType* CodeGenerator::createPolygonStructType(const std::string& udf_func_name,
1102  size_t param_num) {
1103  llvm::Module* module_for_lookup = cgen_state_->module_;
1104  llvm::Function* udf_func = module_for_lookup->getFunction(udf_func_name);
1105 
1106  llvm::StructType* generated_struct_type =
1107  llvm::StructType::get(cgen_state_->context_,
1108  {llvm::Type::getInt8PtrTy(cgen_state_->context_),
1109  llvm::Type::getInt32Ty(cgen_state_->context_),
1110  llvm::Type::getInt8PtrTy(cgen_state_->context_),
1111  llvm::Type::getInt32Ty(cgen_state_->context_),
1112  llvm::Type::getInt32Ty(cgen_state_->context_),
1113  llvm::Type::getInt32Ty(cgen_state_->context_),
1114  llvm::Type::getInt32Ty(cgen_state_->context_)},
1115  false);
1116 
1117  if (udf_func) {
1118  llvm::FunctionType* udf_func_type = udf_func->getFunctionType();
1119  CHECK(param_num < udf_func_type->getNumParams());
1120  llvm::Type* param_pointer_type = udf_func_type->getParamType(param_num);
1121  CHECK(param_pointer_type->isPointerTy());
1122  llvm::Type* param_type = param_pointer_type->getPointerElementType();
1123  CHECK(param_type->isStructTy());
1124  llvm::StructType* struct_type = llvm::cast<llvm::StructType>(param_type);
1125 
1126  CHECK(struct_type->isStructTy());
1127  CHECK_EQ(struct_type->getStructNumElements(), 7u);
1128 
1129  const auto expected_elems = generated_struct_type->elements();
1130  const auto current_elems = struct_type->elements();
1131  for (size_t i = 0; i < expected_elems.size(); i++) {
1132  CHECK_EQ(expected_elems[i], current_elems[i]);
1133  }
1134  if (struct_type->isLiteral()) {
1135  return struct_type;
1136  }
1137 
1138  llvm::StringRef struct_name = struct_type->getStructName();
1139 
1140 #if LLVM_VERSION_MAJOR >= 12
1141  llvm::StructType* polygon_type =
1142  struct_type->getTypeByName(cgen_state_->context_, struct_name);
1143 #else
1144  llvm::StructType* polygon_type = module_for_lookup->getTypeByName(struct_name);
1145 #endif
1146  CHECK(polygon_type);
1147 
1148  return polygon_type;
1149  }
1150  return generated_struct_type;
1151 }
1152 
1153 void CodeGenerator::codegenGeoPolygonArgs(const std::string& udf_func_name,
1154  size_t param_num,
1155  llvm::Value* polygon_buf,
1156  llvm::Value* polygon_size,
1157  llvm::Value* ring_sizes_buf,
1158  llvm::Value* num_rings,
1159  llvm::Value* compression,
1160  llvm::Value* input_srid,
1161  llvm::Value* output_srid,
1162  std::vector<llvm::Value*>& output_args) {
1164  CHECK(polygon_buf);
1165  CHECK(polygon_size);
1166  CHECK(ring_sizes_buf);
1167  CHECK(num_rings);
1168  CHECK(compression);
1169  CHECK(input_srid);
1170  CHECK(output_srid);
1171 
1172  auto& builder = cgen_state_->ir_builder_;
1173 
1174  auto polygon_abstraction = createPolygonStructType(udf_func_name, param_num);
1175  auto alloc_mem = builder.CreateAlloca(polygon_abstraction, nullptr);
1176 
1177  const auto polygon_buf_ptr = builder.CreateStructGEP(polygon_abstraction, alloc_mem, 0);
1178  builder.CreateStore(polygon_buf, polygon_buf_ptr);
1179 
1180  const auto polygon_size_ptr =
1181  builder.CreateStructGEP(polygon_abstraction, alloc_mem, 1);
1182  builder.CreateStore(polygon_size, polygon_size_ptr);
1183 
1184  const auto ring_sizes_buf_ptr =
1185  builder.CreateStructGEP(polygon_abstraction, alloc_mem, 2);
1186  const auto ring_sizes_ptr_ty =
1187  llvm::dyn_cast<llvm::PointerType>(ring_sizes_buf_ptr->getType());
1188  CHECK(ring_sizes_ptr_ty);
1189  builder.CreateStore(
1190  builder.CreateBitCast(ring_sizes_buf, ring_sizes_ptr_ty->getPointerElementType()),
1191  ring_sizes_buf_ptr);
1192 
1193  const auto ring_size_ptr = builder.CreateStructGEP(polygon_abstraction, alloc_mem, 3);
1194  builder.CreateStore(num_rings, ring_size_ptr);
1195 
1196  const auto polygon_compression_ptr =
1197  builder.CreateStructGEP(polygon_abstraction, alloc_mem, 4);
1198  builder.CreateStore(compression, polygon_compression_ptr);
1199 
1200  const auto input_srid_ptr = builder.CreateStructGEP(polygon_abstraction, alloc_mem, 5);
1201  builder.CreateStore(input_srid, input_srid_ptr);
1202 
1203  const auto output_srid_ptr = builder.CreateStructGEP(polygon_abstraction, alloc_mem, 6);
1204  builder.CreateStore(output_srid, output_srid_ptr);
1205 
1206  output_args.push_back(alloc_mem);
1207 }
1208 
1210  const std::string& udf_func_name,
1211  size_t param_num) {
1212  llvm::Function* udf_func = cgen_state_->module_->getFunction(udf_func_name);
1213 
1214  llvm::StructType* generated_struct_type =
1215  llvm::StructType::get(cgen_state_->context_,
1216  {llvm::Type::getInt8PtrTy(cgen_state_->context_),
1217  llvm::Type::getInt32Ty(cgen_state_->context_),
1218  llvm::Type::getInt8PtrTy(cgen_state_->context_),
1219  llvm::Type::getInt32Ty(cgen_state_->context_),
1220  llvm::Type::getInt8PtrTy(cgen_state_->context_),
1221  llvm::Type::getInt32Ty(cgen_state_->context_),
1222  llvm::Type::getInt32Ty(cgen_state_->context_),
1223  llvm::Type::getInt32Ty(cgen_state_->context_),
1224  llvm::Type::getInt32Ty(cgen_state_->context_)},
1225  false);
1226 
1227  if (udf_func) {
1228  llvm::FunctionType* udf_func_type = udf_func->getFunctionType();
1229  CHECK(param_num < udf_func_type->getNumParams());
1230  llvm::Type* param_pointer_type = udf_func_type->getParamType(param_num);
1231  CHECK(param_pointer_type->isPointerTy());
1232  llvm::Type* param_type = param_pointer_type->getPointerElementType();
1233  CHECK(param_type->isStructTy());
1234  llvm::StructType* struct_type = llvm::cast<llvm::StructType>(param_type);
1235  CHECK(struct_type->isStructTy());
1236  CHECK_EQ(struct_type->getStructNumElements(), 9u);
1237  const auto expected_elems = generated_struct_type->elements();
1238  const auto current_elems = struct_type->elements();
1239  for (size_t i = 0; i < expected_elems.size(); i++) {
1240  CHECK_EQ(expected_elems[i], current_elems[i]);
1241  }
1242  if (struct_type->isLiteral()) {
1243  return struct_type;
1244  }
1245  llvm::StringRef struct_name = struct_type->getStructName();
1246 
1247 #if LLVM_VERSION_MAJOR >= 12
1248  llvm::StructType* polygon_type =
1249  struct_type->getTypeByName(cgen_state_->context_, struct_name);
1250 #else
1251  llvm::StructType* polygon_type = cgen_state_->module_->getTypeByName(struct_name);
1252 #endif
1253  CHECK(polygon_type);
1254 
1255  return polygon_type;
1256  }
1257  return generated_struct_type;
1258 }
1259 
1260 void CodeGenerator::codegenGeoMultiPolygonArgs(const std::string& udf_func_name,
1261  size_t param_num,
1262  llvm::Value* polygon_coords,
1263  llvm::Value* polygon_coords_size,
1264  llvm::Value* ring_sizes_buf,
1265  llvm::Value* ring_sizes,
1266  llvm::Value* polygon_bounds,
1267  llvm::Value* polygon_bounds_sizes,
1268  llvm::Value* compression,
1269  llvm::Value* input_srid,
1270  llvm::Value* output_srid,
1271  std::vector<llvm::Value*>& output_args) {
1273  CHECK(polygon_coords);
1274  CHECK(polygon_coords_size);
1275  CHECK(ring_sizes_buf);
1276  CHECK(ring_sizes);
1277  CHECK(polygon_bounds);
1278  CHECK(polygon_bounds_sizes);
1279  CHECK(compression);
1280  CHECK(input_srid);
1281  CHECK(output_srid);
1282 
1283  auto& builder = cgen_state_->ir_builder_;
1284 
1285  auto multi_polygon_abstraction = createMultiPolygonStructType(udf_func_name, param_num);
1286  auto alloc_mem = builder.CreateAlloca(multi_polygon_abstraction, nullptr);
1287 
1288  const auto polygon_coords_ptr =
1289  builder.CreateStructGEP(multi_polygon_abstraction, alloc_mem, 0);
1290  builder.CreateStore(polygon_coords, polygon_coords_ptr);
1291 
1292  const auto polygon_coords_size_ptr =
1293  builder.CreateStructGEP(multi_polygon_abstraction, alloc_mem, 1);
1294  builder.CreateStore(polygon_coords_size, polygon_coords_size_ptr);
1295 
1296  const auto ring_sizes_buf_ptr =
1297  builder.CreateStructGEP(multi_polygon_abstraction, alloc_mem, 2);
1298  const auto ring_sizes_ptr_ty =
1299  llvm::dyn_cast<llvm::PointerType>(ring_sizes_buf_ptr->getType());
1300  CHECK(ring_sizes_ptr_ty);
1301  builder.CreateStore(
1302  builder.CreateBitCast(ring_sizes_buf, ring_sizes_ptr_ty->getPointerElementType()),
1303  ring_sizes_buf_ptr);
1304 
1305  const auto ring_sizes_ptr =
1306  builder.CreateStructGEP(multi_polygon_abstraction, alloc_mem, 3);
1307  builder.CreateStore(ring_sizes, ring_sizes_ptr);
1308 
1309  const auto polygon_bounds_buf_ptr =
1310  builder.CreateStructGEP(multi_polygon_abstraction, alloc_mem, 4);
1311  const auto bounds_ptr_ty =
1312  llvm::dyn_cast<llvm::PointerType>(polygon_bounds_buf_ptr->getType());
1313  CHECK(bounds_ptr_ty);
1314  builder.CreateStore(
1315  builder.CreateBitCast(polygon_bounds, bounds_ptr_ty->getPointerElementType()),
1316  polygon_bounds_buf_ptr);
1317 
1318  const auto polygon_bounds_sizes_ptr =
1319  builder.CreateStructGEP(multi_polygon_abstraction, alloc_mem, 5);
1320  builder.CreateStore(polygon_bounds_sizes, polygon_bounds_sizes_ptr);
1321 
1322  const auto polygon_compression_ptr =
1323  builder.CreateStructGEP(multi_polygon_abstraction, alloc_mem, 6);
1324  builder.CreateStore(compression, polygon_compression_ptr);
1325 
1326  const auto input_srid_ptr =
1327  builder.CreateStructGEP(multi_polygon_abstraction, alloc_mem, 7);
1328  builder.CreateStore(input_srid, input_srid_ptr);
1329 
1330  const auto output_srid_ptr =
1331  builder.CreateStructGEP(multi_polygon_abstraction, alloc_mem, 8);
1332  builder.CreateStore(output_srid, output_srid_ptr);
1333 
1334  output_args.push_back(alloc_mem);
1335 }
1336 
1337 // Generate CAST operations for arguments in `orig_arg_lvs` to the types required by
1338 // `ext_func_sig`.
1340  const Analyzer::FunctionOper* function_oper,
1341  const ExtensionFunction* ext_func_sig,
1342  const std::vector<llvm::Value*>& orig_arg_lvs,
1343  const std::vector<size_t>& orig_arg_lvs_index,
1344  const std::unordered_map<llvm::Value*, llvm::Value*>& const_arr_size,
1345  const CompilationOptions& co) {
1347  CHECK(ext_func_sig);
1348  const auto& ext_func_args = ext_func_sig->getInputArgs();
1349  CHECK_LE(function_oper->getArity(), ext_func_args.size());
1350  const auto func_ti = function_oper->get_type_info();
1351  std::vector<llvm::Value*> args;
1352  /*
1353  i: argument in RA for the function operand
1354  j: extra offset in ext_func_args
1355  k: origin_arg_lvs counter, equal to orig_arg_lvs_index[i]
1356  ij: ext_func_args counter, equal to i + j
1357  dj: offset when UDF implementation first argument corresponds to return value
1358  */
1359  for (size_t i = 0, j = 0, dj = (func_ti.is_buffer() ? 1 : 0);
1360  i < function_oper->getArity();
1361  ++i) {
1362  size_t k = orig_arg_lvs_index[i];
1363  size_t ij = i + j;
1364  const auto arg = function_oper->getArg(i);
1365  const auto ext_func_arg = ext_func_args[ij];
1366  const auto& arg_ti = arg->get_type_info();
1367  llvm::Value* arg_lv{nullptr};
1368  if (arg_ti.is_bytes()) {
1369  CHECK(ext_func_arg == ExtArgumentType::TextEncodingNone)
1370  << ::toString(ext_func_arg);
1371  const auto ptr_lv = orig_arg_lvs[k + 1];
1372  const auto len_lv = orig_arg_lvs[k + 2];
1373  auto& builder = cgen_state_->ir_builder_;
1374  auto string_buf_arg = builder.CreatePointerCast(
1375  ptr_lv, llvm::Type::getInt8PtrTy(cgen_state_->context_));
1376  auto string_size_arg =
1377  builder.CreateZExt(len_lv, get_int_type(64, cgen_state_->context_));
1378  codegenBufferArgs(ext_func_sig->getName(),
1379  ij + dj,
1380  string_buf_arg,
1381  string_size_arg,
1382  nullptr,
1383  args);
1384  } else if (arg_ti.is_array()) {
1385  bool const_arr = (const_arr_size.count(orig_arg_lvs[k]) > 0);
1386  const auto elem_ti = arg_ti.get_elem_type();
1387  // TODO: switch to fast fixlen variants
1388  const auto ptr_lv = (const_arr)
1389  ? orig_arg_lvs[k]
1391  "array_buff",
1392  llvm::Type::getInt8PtrTy(cgen_state_->context_),
1393  {orig_arg_lvs[k], posArg(arg)});
1394  const auto len_lv =
1395  (const_arr) ? const_arr_size.at(orig_arg_lvs[k])
1397  "array_size",
1399  {orig_arg_lvs[k],
1400  posArg(arg),
1401  cgen_state_->llInt(log2_bytes(elem_ti.get_logical_size()))});
1402 
1403  if (is_ext_arg_type_pointer(ext_func_arg)) {
1404  args.push_back(castArrayPointer(ptr_lv, elem_ti));
1405  args.push_back(cgen_state_->ir_builder_.CreateZExt(
1406  len_lv, get_int_type(64, cgen_state_->context_)));
1407  j++;
1408  } else if (is_ext_arg_type_array(ext_func_arg)) {
1409  auto array_buf_arg = castArrayPointer(ptr_lv, elem_ti);
1410  auto& builder = cgen_state_->ir_builder_;
1411  auto array_size_arg =
1412  builder.CreateZExt(len_lv, get_int_type(64, cgen_state_->context_));
1413  auto array_null_arg =
1414  cgen_state_->emitExternalCall("array_is_null",
1416  {orig_arg_lvs[k], posArg(arg)});
1417  codegenBufferArgs(ext_func_sig->getName(),
1418  ij + dj,
1419  array_buf_arg,
1420  array_size_arg,
1421  array_null_arg,
1422  args);
1423  } else {
1424  UNREACHABLE();
1425  }
1426 
1427  } else if (arg_ti.is_geometry()) {
1428  auto geo_expr_arg = dynamic_cast<const Analyzer::GeoExpr*>(arg);
1429  if (geo_expr_arg) {
1430  auto ptr_lv = cgen_state_->ir_builder_.CreateBitCast(
1431  orig_arg_lvs[k], llvm::Type::getInt8PtrTy(cgen_state_->context_));
1432  args.push_back(ptr_lv);
1433  // TODO: remove when we normalize extension functions geo sizes to int32
1434  auto size_lv = cgen_state_->ir_builder_.CreateSExt(
1435  orig_arg_lvs[k + 1], llvm::Type::getInt64Ty(cgen_state_->context_));
1436  args.push_back(size_lv);
1437  j++;
1438  continue;
1439  }
1440  // Coords
1441  bool const_arr = (const_arr_size.count(orig_arg_lvs[k]) > 0);
1442  // NOTE(adb): We're generating code to handle the TINYINT array only -- the actual
1443  // geo encoding (or lack thereof) does not matter here
1444  const auto elem_ti = SQLTypeInfo(SQLTypes::kARRAY,
1445  0,
1446  0,
1447  false,
1449  0,
1451  .get_elem_type();
1452  llvm::Value* ptr_lv;
1453  llvm::Value* len_lv;
1454  int32_t fixlen = -1;
1455  if (arg_ti.get_type() == kPOINT) {
1456  const auto col_var = dynamic_cast<const Analyzer::ColumnVar*>(arg);
1457  if (col_var) {
1458  const auto coords_cd = executor()->getPhysicalColumnDescriptor(col_var, 1);
1459  if (coords_cd && coords_cd->columnType.get_type() == kARRAY) {
1460  fixlen = coords_cd->columnType.get_size();
1461  }
1462  }
1463  }
1464  if (fixlen > 0) {
1465  ptr_lv =
1466  cgen_state_->emitExternalCall("fast_fixlen_array_buff",
1467  llvm::Type::getInt8PtrTy(cgen_state_->context_),
1468  {orig_arg_lvs[k], posArg(arg)});
1469  len_lv = cgen_state_->llInt(int32_t(fixlen));
1470  } else {
1471  // TODO: remove const_arr and related code if it's not needed
1472  ptr_lv = (const_arr) ? orig_arg_lvs[k]
1474  "array_buff",
1475  llvm::Type::getInt8PtrTy(cgen_state_->context_),
1476  {orig_arg_lvs[k], posArg(arg)});
1477  len_lv = (const_arr)
1478  ? const_arr_size.at(orig_arg_lvs[k])
1480  "array_size",
1482  {orig_arg_lvs[k],
1483  posArg(arg),
1484  cgen_state_->llInt(log2_bytes(elem_ti.get_logical_size()))});
1485  }
1486 
1487  if (is_ext_arg_type_geo(ext_func_arg)) {
1488  if (arg_ti.get_type() == kPOINT || arg_ti.get_type() == kLINESTRING ||
1489  arg_ti.get_type() == kMULTIPOINT) {
1490  auto array_buf_arg = castArrayPointer(ptr_lv, elem_ti);
1491  auto compression_val = codegenCompression(arg_ti);
1492  auto input_srid_val = cgen_state_->llInt(arg_ti.get_input_srid());
1493  auto output_srid_val = cgen_state_->llInt(arg_ti.get_output_srid());
1494 
1495  if (arg_ti.get_type() == kPOINT) {
1496  CHECK_EQ(k, ij);
1497  codegenGeoPointArgs(ext_func_sig->getName(),
1498  ij + dj,
1499  array_buf_arg,
1500  len_lv,
1501  compression_val,
1502  input_srid_val,
1503  output_srid_val,
1504  args);
1505  } else if (arg_ti.get_type() == kMULTIPOINT) {
1506  CHECK_EQ(k, ij);
1507  codegenGeoMultiPointArgs(ext_func_sig->getName(),
1508  ij + dj,
1509  array_buf_arg,
1510  len_lv,
1511  compression_val,
1512  input_srid_val,
1513  output_srid_val,
1514  args);
1515  } else {
1516  CHECK_EQ(k, ij);
1517  codegenGeoLineStringArgs(ext_func_sig->getName(),
1518  ij + dj,
1519  array_buf_arg,
1520  len_lv,
1521  compression_val,
1522  input_srid_val,
1523  output_srid_val,
1524  args);
1525  }
1526  }
1527  } else {
1528  CHECK(ext_func_arg == ExtArgumentType::PInt8);
1529  args.push_back(castArrayPointer(ptr_lv, elem_ti));
1530  args.push_back(cgen_state_->ir_builder_.CreateZExt(
1531  len_lv, get_int_type(64, cgen_state_->context_)));
1532  j++;
1533  }
1534 
1535  switch (arg_ti.get_type()) {
1536  case kPOINT:
1537  case kMULTIPOINT:
1538  case kLINESTRING:
1539  break;
1540  case kMULTILINESTRING: {
1541  if (ext_func_arg == ExtArgumentType::GeoMultiLineString) {
1542  auto multi_linestring_coords = castArrayPointer(ptr_lv, elem_ti);
1543  auto compression_val = codegenCompression(arg_ti);
1544  auto input_srid_val = cgen_state_->llInt(arg_ti.get_input_srid());
1545  auto output_srid_val = cgen_state_->llInt(arg_ti.get_output_srid());
1546 
1547  auto [linestring_sizes, linestring_sizes_size] =
1548  codegenArrayBuff(orig_arg_lvs[k + 1],
1549  posArg(arg),
1551  /*cast_and_extend=*/false);
1552  CHECK_EQ(k, ij);
1553  codegenGeoMultiLineStringArgs(ext_func_sig->getName(),
1554  ij + dj,
1555  multi_linestring_coords,
1556  len_lv,
1557  linestring_sizes,
1558  linestring_sizes_size,
1559  compression_val,
1560  input_srid_val,
1561  output_srid_val,
1562  args);
1563  } else {
1564  CHECK(ext_func_arg == ExtArgumentType::PInt8);
1565  // Linestring Sizes
1566  auto const_arr = const_arr_size.count(orig_arg_lvs[k + 1]) > 0;
1567  auto [linestring_sizes, linestring_sizes_size] =
1568  (const_arr) ? std::make_pair(orig_arg_lvs[k + 1],
1569  const_arr_size.at(orig_arg_lvs[k + 1]))
1570  : codegenArrayBuff(orig_arg_lvs[k + 1],
1571  posArg(arg),
1573  /*cast_and_extend=*/true);
1574  args.push_back(linestring_sizes);
1575  args.push_back(linestring_sizes_size);
1576  j += 2;
1577  }
1578  break;
1579  }
1580  case kPOLYGON: {
1581  if (ext_func_arg == ExtArgumentType::GeoPolygon) {
1582  auto array_buf_arg = castArrayPointer(ptr_lv, elem_ti);
1583  auto compression_val = codegenCompression(arg_ti);
1584  auto input_srid_val = cgen_state_->llInt(arg_ti.get_input_srid());
1585  auto output_srid_val = cgen_state_->llInt(arg_ti.get_output_srid());
1586 
1587  auto [ring_size_buff, ring_size] =
1588  codegenArrayBuff(orig_arg_lvs[k + 1],
1589  posArg(arg),
1591  /*cast_and_extend=*/false);
1592  CHECK_EQ(k, ij);
1593  codegenGeoPolygonArgs(ext_func_sig->getName(),
1594  ij + dj,
1595  array_buf_arg,
1596  len_lv,
1597  ring_size_buff,
1598  ring_size,
1599  compression_val,
1600  input_srid_val,
1601  output_srid_val,
1602  args);
1603  } else {
1604  CHECK(ext_func_arg == ExtArgumentType::PInt8);
1605  // Ring Sizes
1606  auto const_arr = const_arr_size.count(orig_arg_lvs[k + 1]) > 0;
1607  auto [ring_size_buff, ring_size] =
1608  (const_arr) ? std::make_pair(orig_arg_lvs[k + 1],
1609  const_arr_size.at(orig_arg_lvs[k + 1]))
1610  : codegenArrayBuff(orig_arg_lvs[k + 1],
1611  posArg(arg),
1613  /*cast_and_extend=*/true);
1614  args.push_back(ring_size_buff);
1615  args.push_back(ring_size);
1616  j += 2;
1617  }
1618  break;
1619  }
1620  case kMULTIPOLYGON: {
1621  if (ext_func_arg == ExtArgumentType::GeoMultiPolygon) {
1622  auto array_buf_arg = castArrayPointer(ptr_lv, elem_ti);
1623  auto compression_val = codegenCompression(arg_ti);
1624  auto input_srid_val = cgen_state_->llInt(arg_ti.get_input_srid());
1625  auto output_srid_val = cgen_state_->llInt(arg_ti.get_output_srid());
1626 
1627  auto [ring_size_buff, ring_size] =
1628  codegenArrayBuff(orig_arg_lvs[k + 1],
1629  posArg(arg),
1631  /*cast_and_extend=*/false);
1632 
1633  auto [poly_bounds_buff, poly_bounds_size] =
1634  codegenArrayBuff(orig_arg_lvs[k + 2],
1635  posArg(arg),
1637  /*cast_and_extend=*/false);
1638  CHECK_EQ(k, ij);
1639  codegenGeoMultiPolygonArgs(ext_func_sig->getName(),
1640  ij + dj,
1641  array_buf_arg,
1642  len_lv,
1643  ring_size_buff,
1644  ring_size,
1645  poly_bounds_buff,
1646  poly_bounds_size,
1647  compression_val,
1648  input_srid_val,
1649  output_srid_val,
1650  args);
1651  } else {
1652  CHECK(ext_func_arg == ExtArgumentType::PInt8);
1653  // Ring Sizes
1654  {
1655  auto const_arr = const_arr_size.count(orig_arg_lvs[k + 1]) > 0;
1656  auto [ring_size_buff, ring_size] =
1657  (const_arr) ? std::make_pair(orig_arg_lvs[k + 1],
1658  const_arr_size.at(orig_arg_lvs[k + 1]))
1659  : codegenArrayBuff(orig_arg_lvs[k + 1],
1660  posArg(arg),
1662  /*cast_and_extend=*/true);
1663 
1664  args.push_back(ring_size_buff);
1665  args.push_back(ring_size);
1666  }
1667  // Poly Rings
1668  {
1669  auto const_arr = const_arr_size.count(orig_arg_lvs[k + 2]) > 0;
1670  auto [poly_bounds_buff, poly_bounds_size] =
1671  (const_arr)
1672  ? std::make_pair(orig_arg_lvs[k + 2],
1673  const_arr_size.at(orig_arg_lvs[k + 2]))
1674  : codegenArrayBuff(
1675  orig_arg_lvs[k + 2], posArg(arg), SQLTypes::kINT, true);
1676 
1677  args.push_back(poly_bounds_buff);
1678  args.push_back(poly_bounds_size);
1679  }
1680  j += 4;
1681  }
1682  break;
1683  }
1684  default:
1685  CHECK(false);
1686  }
1687  } else {
1688  CHECK(is_ext_arg_type_scalar(ext_func_arg));
1689  const auto arg_target_ti = ext_arg_type_to_type_info(ext_func_arg);
1690  if (arg_ti.get_type() != arg_target_ti.get_type()) {
1691  arg_lv = codegenCast(orig_arg_lvs[k], arg_ti, arg_target_ti, false, co);
1692  } else {
1693  arg_lv = orig_arg_lvs[k];
1694  }
1695  CHECK_EQ(arg_lv->getType(),
1696  ext_arg_type_to_llvm_type(ext_func_arg, cgen_state_->context_));
1697  args.push_back(arg_lv);
1698  }
1699  }
1700  return args;
1701 }
1702 
1703 llvm::Value* CodeGenerator::castArrayPointer(llvm::Value* ptr,
1704  const SQLTypeInfo& elem_ti) {
1706  if (elem_ti.get_type() == kFLOAT) {
1707  return cgen_state_->ir_builder_.CreatePointerCast(
1708  ptr, llvm::Type::getFloatPtrTy(cgen_state_->context_));
1709  }
1710  if (elem_ti.get_type() == kDOUBLE) {
1711  return cgen_state_->ir_builder_.CreatePointerCast(
1712  ptr, llvm::Type::getDoublePtrTy(cgen_state_->context_));
1713  }
1714  CHECK(elem_ti.is_integer() || elem_ti.is_boolean() ||
1715  (elem_ti.is_string() && elem_ti.get_compression() == kENCODING_DICT));
1716  switch (elem_ti.get_size()) {
1717  case 1:
1718  return cgen_state_->ir_builder_.CreatePointerCast(
1719  ptr, llvm::Type::getInt8PtrTy(cgen_state_->context_));
1720  case 2:
1721  return cgen_state_->ir_builder_.CreatePointerCast(
1722  ptr, llvm::Type::getInt16PtrTy(cgen_state_->context_));
1723  case 4:
1724  return cgen_state_->ir_builder_.CreatePointerCast(
1725  ptr, llvm::Type::getInt32PtrTy(cgen_state_->context_));
1726  case 8:
1727  return cgen_state_->ir_builder_.CreatePointerCast(
1728  ptr, llvm::Type::getInt64PtrTy(cgen_state_->context_));
1729  default:
1730  CHECK(false);
1731  }
1732  return nullptr;
1733 }
llvm::StructType * createLineStringStructType(const std::string &udf_func_name, size_t param_num)
void codegenGeoMultiPolygonArgs(const std::string &udf_func_name, size_t param_num, llvm::Value *polygon_coords, llvm::Value *polygon_coords_size, llvm::Value *ring_sizes_buf, llvm::Value *ring_sizes, llvm::Value *polygon_bounds, llvm::Value *polygon_bounds_sizes, llvm::Value *compression, llvm::Value *input_srid, llvm::Value *output_srid, std::vector< llvm::Value * > &output_args)
#define CHECK_EQ(x, y)
Definition: Logger.h:230
llvm::StructType * get_buffer_struct_type(CgenState *cgen_state, const std::string &ext_func_name, size_t param_num, llvm::Type *elem_type, bool has_is_null)
HOST DEVICE int get_size() const
Definition: sqltypes.h:414
bool is_ext_arg_type_scalar(const ExtArgumentType ext_arg_type)
llvm::BasicBlock * args_notnull_bb
size_t getArity() const
Definition: Analyzer.h:2260
SQLTypes
Definition: sqltypes.h:52
std::unique_ptr< llvm::Module > udf_gpu_module
CgenState * cgen_state_
const ExtArgumentType getRet() const
void codegenGeoPolygonArgs(const std::string &udf_func_name, size_t param_num, llvm::Value *polygon_buf, llvm::Value *polygon_size, llvm::Value *ring_sizes_buf, llvm::Value *num_rings, llvm::Value *compression, llvm::Value *input_srid, llvm::Value *output_srid, std::vector< llvm::Value * > &output_args)
llvm::StructType * createMultiPointStructType(const std::string &udf_func_name, size_t param_num)
#define LOG(tag)
Definition: Logger.h:216
std::vector< llvm::Value * > codegenFunctionOperCastArgs(const Analyzer::FunctionOper *, const ExtensionFunction *, const std::vector< llvm::Value * > &, const std::vector< size_t > &, const std::unordered_map< llvm::Value *, llvm::Value * > &, const CompilationOptions &)
llvm::StructType * createMultiLineStringStructType(const std::string &udf_func_name, size_t param_num)
llvm::Value * emitExternalCall(const std::string &fname, llvm::Type *ret_type, const std::vector< llvm::Value * > args, const std::vector< llvm::Attribute::AttrKind > &fnattrs={}, const bool has_struct_return=false)
Definition: CgenState.h:217
llvm::Value * codegenFunctionOperNullArg(const Analyzer::FunctionOper *, const std::vector< llvm::Value * > &)
llvm::IRBuilder ir_builder_
Definition: CgenState.h:441
llvm::Value * posArg(const Analyzer::Expr *) const
Definition: ColumnIR.cpp:550
llvm::Value * castArrayPointer(llvm::Value *ptr, const SQLTypeInfo &elem_ti)
#define UNREACHABLE()
Definition: Logger.h:266
#define CHECK_GE(x, y)
Definition: Logger.h:235
Definition: sqldefs.h:48
llvm::Type * get_fp_type(const int width, llvm::LLVMContext &context)
llvm::StructType * createPointStructType(const std::string &udf_func_name, size_t param_num)
bool call_requires_custom_type_handling(const Analyzer::FunctionOper *function_oper)
std::string toString(const QueryDescriptionType &type)
Definition: Types.h:64
const std::string getName(bool keep_suffix=true) const
HOST DEVICE SQLTypes get_type() const
Definition: sqltypes.h:404
llvm::Type * get_int_type(const int width, llvm::LLVMContext &context)
bool ext_func_call_requires_nullcheck(const Analyzer::FunctionOper *function_oper)
SQLTypeInfo get_sql_type_from_llvm_type(const llvm::Type *ll_type)
std::vector< FunctionOperValue > ext_call_cache_
Definition: CgenState.h:447
void codegenBufferArgs(const std::string &udf_func_name, size_t param_num, llvm::Value *buffer_buf, llvm::Value *buffer_size, llvm::Value *buffer_is_null, std::vector< llvm::Value * > &output_args)
RUNTIME_EXPORT void register_buffer_with_executor_rsm(int64_t exec, int8_t *buffer)
std::pair< llvm::Value *, llvm::Value * > codegenArrayBuff(llvm::Value *chunk, llvm::Value *row_pos, SQLTypes array_type, bool cast_and_extend)
llvm::Module * module_
Definition: CgenState.h:430
Supported runtime functions management and retrieval.
llvm::LLVMContext & context_
Definition: CgenState.h:439
llvm::Function * current_func_
Definition: CgenState.h:433
std::tuple< ArgNullcheckBBs, llvm::Value * > beginArgsNullcheck(const Analyzer::FunctionOper *function_oper, const std::vector< llvm::Value * > &orig_arg_lvs)
bool is_integer() const
Definition: sqltypes.h:602
llvm::ConstantInt * inlineIntNull(const SQLTypeInfo &)
Definition: CgenState.cpp:64
bool is_ext_arg_type_geo(const ExtArgumentType ext_arg_type)
void codegenGeoMultiPointArgs(const std::string &udf_func_name, size_t param_num, llvm::Value *multi_point_buf, llvm::Value *multi_point_size, llvm::Value *compression, llvm::Value *input_srid, llvm::Value *output_srid, std::vector< llvm::Value * > &output_args)
bool is_ext_arg_type_array(const ExtArgumentType ext_arg_type)
llvm::Value * codegenFunctionOper(const Analyzer::FunctionOper *, const CompilationOptions &)
llvm::Type * get_llvm_type_from_sql_array_type(const SQLTypeInfo ti, llvm::LLVMContext &ctx)
bool is_boolean() const
Definition: sqltypes.h:607
llvm::BasicBlock * args_null_bb
#define AUTOMATIC_IR_METADATA(CGENSTATE)
llvm::Type * ext_arg_type_to_llvm_type(const ExtArgumentType ext_arg_type, llvm::LLVMContext &ctx)
void codegenGeoMultiLineStringArgs(const std::string &udf_func_name, size_t param_num, llvm::Value *multi_linestring_coords, llvm::Value *multi_linestring_size, llvm::Value *linestring_sizes, llvm::Value *linestring_sizes_size, llvm::Value *compression, llvm::Value *input_srid, llvm::Value *output_srid, std::vector< llvm::Value * > &output_args)
std::tuple< T, std::vector< SQLTypeInfo > > bind_function(std::string name, Analyzer::ExpressionPtrVector func_args, const std::vector< T > &ext_funcs, const std::string processor)
Argument type based extension function binding.
const SQLTypeInfo & get_type_info() const
Definition: Analyzer.h:82
llvm::Value * emitCall(const std::string &fname, const std::vector< llvm::Value * > &args)
Definition: CgenState.cpp:219
bool is_buffer() const
Definition: sqltypes.h:632
ExecutorDeviceType device_type
void codegenGeoPointArgs(const std::string &udf_func_name, size_t param_num, llvm::Value *point_buf, llvm::Value *point_size, llvm::Value *compression, llvm::Value *input_srid, llvm::Value *output_srid, std::vector< llvm::Value * > &output_args)
#define RUNTIME_EXPORT
std::vector< llvm::Value * > codegen(const Analyzer::Expr *, const bool fetch_columns, const CompilationOptions &)
Definition: IRCodegen.cpp:30
#define CHECK_LE(x, y)
Definition: Logger.h:233
HOST DEVICE EncodingType get_compression() const
Definition: sqltypes.h:412
std::string serialize_llvm_object(const T *llvm_obj)
bool isLocalAlloc() const
Definition: Analyzer.h:2492
llvm::StructType * createPolygonStructType(const std::string &udf_func_name, size_t param_num)
const Analyzer::Expr * getArg(const size_t i) const
Definition: Analyzer.h:2262
const Expr * get_operand() const
Definition: Analyzer.h:379
llvm::Value * endArgsNullcheck(const ArgNullcheckBBs &, llvm::Value *, llvm::Value *, const Analyzer::FunctionOper *)
const std::vector< ExtArgumentType > & getInputArgs() const
std::unique_ptr< llvm::Module > udf_cpu_module
HOST DEVICE int get_comp_param() const
Definition: sqltypes.h:413
llvm::Value * codegenFunctionOperWithCustomTypeHandling(const Analyzer::FunctionOperWithCustomTypeHandling *, const CompilationOptions &)
bool is_bytes() const
Definition: sqltypes.h:623
llvm::ConstantInt * llInt(const T v) const
Definition: CgenState.h:306
#define CHECK(condition)
Definition: Logger.h:222
llvm::Value * codegenIsNullNumber(llvm::Value *, const SQLTypeInfo &)
Definition: LogicalIR.cpp:409
uint64_t exp_to_scale(const unsigned exp)
llvm::Value * codegenCompression(const SQLTypeInfo &type_info)
llvm::Value * codegenCast(const Analyzer::UOper *, const CompilationOptions &)
Definition: CastIR.cpp:21
uint32_t log2_bytes(const uint32_t bytes)
Definition: Execute.h:176
Definition: sqltypes.h:59
bool is_string() const
Definition: sqltypes.h:600
std::string getName() const
Definition: Analyzer.h:2258
void codegenGeoLineStringArgs(const std::string &udf_func_name, size_t param_num, llvm::Value *line_string_buf, llvm::Value *line_string_size, llvm::Value *compression, llvm::Value *input_srid, llvm::Value *output_srid, std::vector< llvm::Value * > &output_args)
bool is_ext_arg_type_pointer(const ExtArgumentType ext_arg_type)
SQLTypeInfo get_elem_type() const
Definition: sqltypes.h:981
bool is_decimal() const
Definition: sqltypes.h:603
int get_physical_coord_cols() const
Definition: sqltypes.h:454
SQLTypeInfo ext_arg_type_to_type_info(const ExtArgumentType ext_arg_type)
llvm::ConstantFP * inlineFpNull(const SQLTypeInfo &)
Definition: CgenState.cpp:106
Executor * executor() const
llvm::StructType * createMultiPolygonStructType(const std::string &udf_func_name, size_t param_num)