OmniSciDB  06b3bd477c
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ExtensionsIR.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2017 MapD Technologies, 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"
21 
22 #pragma GCC diagnostic push
23 #pragma GCC diagnostic ignored "-Wreturn-type-c-linkage"
24 #include "ExtensionFunctions.hpp"
26 #pragma GCC diagnostic pop
27 
28 #include <tuple>
29 
30 extern std::unique_ptr<llvm::Module> udf_gpu_module;
31 extern std::unique_ptr<llvm::Module> udf_cpu_module;
32 
33 namespace {
34 
36  const std::string& ext_func_name,
37  llvm::Type* array_type,
38  size_t param_num) {
39  llvm::Function* udf_func = cgen_state->module_->getFunction(ext_func_name);
40  CHECK(array_type);
41  CHECK(array_type->isPointerTy());
42 
43  llvm::StructType* generated_struct_type =
44  llvm::StructType::get(cgen_state->context_,
45  {array_type,
46  llvm::Type::getInt64Ty(cgen_state->context_),
47  llvm::Type::getInt8Ty(cgen_state->context_)},
48  false);
49  if (udf_func) {
50  // Compare expected array struct type with type from the function definition from the
51  // UDF module, but use the type from the 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(), size_t(3))
60  << serialize_llvm_object(struct_type);
61 
62  const auto expected_elems = generated_struct_type->elements();
63  const auto current_elems = struct_type->elements();
64  for (size_t i = 0; i < expected_elems.size(); i++) {
65  CHECK_EQ(expected_elems[i], current_elems[i]);
66  }
67 
68  if (struct_type->isLiteral()) {
69  return struct_type;
70  }
71 
72  llvm::StringRef struct_name = struct_type->getStructName();
73  return cgen_state->module_->getTypeByName(struct_name);
74  }
75 
76  return generated_struct_type;
77 }
78 
80  llvm::LLVMContext& ctx) {
81  switch (ext_arg_type) {
82  case ExtArgumentType::Bool: // pass thru to Int8
84  return get_int_type(8, ctx);
86  return get_int_type(16, ctx);
88  return get_int_type(32, ctx);
90  return get_int_type(64, ctx);
92  return llvm::Type::getFloatTy(ctx);
94  return llvm::Type::getDoubleTy(ctx);
96  return llvm::Type::getVoidTy(ctx);
98  return llvm::Type::getVoidTy(ctx);
100  return llvm::Type::getVoidTy(ctx);
102  return llvm::Type::getVoidTy(ctx);
104  return llvm::Type::getVoidTy(ctx);
106  return llvm::Type::getVoidTy(ctx);
107  default:
108  CHECK(false);
109  }
110  CHECK(false);
111  return nullptr;
112 }
113 
115  CHECK(ll_type);
116  const auto bits = ll_type->getPrimitiveSizeInBits();
117 
118  if (ll_type->isFloatingPointTy()) {
119  switch (bits) {
120  case 32:
121  return SQLTypeInfo(kFLOAT, false);
122  case 64:
123  return SQLTypeInfo(kDOUBLE, false);
124  default:
125  LOG(FATAL) << "Unsupported llvm floating point type: " << bits
126  << ", only 32 and 64 bit floating point is supported.";
127  }
128  } else {
129  switch (bits) {
130  case 1:
131  return SQLTypeInfo(kBOOLEAN, false);
132  case 8:
133  return SQLTypeInfo(kTINYINT, false);
134  case 16:
135  return SQLTypeInfo(kSMALLINT, false);
136  case 32:
137  return SQLTypeInfo(kINT, false);
138  case 64:
139  return SQLTypeInfo(kBIGINT, false);
140  default:
141  LOG(FATAL) << "Unrecognized llvm type for SQL type: "
142  << bits; // TODO let's get the real name here
143  }
144  }
145  UNREACHABLE();
146  return SQLTypeInfo();
147 }
148 
150  llvm::LLVMContext& ctx) {
151  CHECK(ti.is_array());
152  const auto& elem_ti = ti.get_elem_type();
153  if (elem_ti.is_fp()) {
154  switch (elem_ti.get_size()) {
155  case 4:
156  return llvm::Type::getFloatPtrTy(ctx);
157  case 8:
158  return llvm::Type::getDoublePtrTy(ctx);
159  }
160  }
161  CHECK(elem_ti.is_integer());
162  switch (elem_ti.get_size()) {
163  case 1:
164  return llvm::Type::getInt8PtrTy(ctx);
165  case 2:
166  return llvm::Type::getInt16PtrTy(ctx);
167  case 4:
168  return llvm::Type::getInt32PtrTy(ctx);
169  case 8:
170  return llvm::Type::getInt64PtrTy(ctx);
171  }
172 
173  UNREACHABLE();
174  return nullptr;
175 }
176 
178  const auto& func_ti = function_oper->get_type_info();
179  for (size_t i = 0; i < function_oper->getArity(); ++i) {
180  const auto arg = function_oper->getArg(i);
181  const auto& arg_ti = arg->get_type_info();
182  if (func_ti.is_array() && arg_ti.is_array()) {
183  // If the function returns an array and any of the arguments are arrays, allow NULL
184  // scalars.
185  // TODO: Make this a property of the FunctionOper following `RETURN NULL ON NULL`
186  // semantics.
187  return false;
188  } else if (!arg_ti.get_notnull() && !arg_ti.is_array()) {
189  // Nullable geometry args will trigger a null check
190  return true;
191  } else {
192  continue;
193  }
194  }
195  return false;
196 }
197 
198 } // namespace
199 
200 #include "../Shared/sql_type_to_string.h"
201 
202 extern "C" void register_buffer_with_executor_rsm(int64_t exec, int8_t* buffer) {
203  Executor* exec_ptr = reinterpret_cast<Executor*>(exec);
204  if (buffer != nullptr) {
205  exec_ptr->getRowSetMemoryOwner()->addVarlenBuffer(buffer);
206  }
207 }
208 
210  const Analyzer::FunctionOper* function_oper,
211  const CompilationOptions& co) {
212  auto ext_func_sig = bind_function(function_oper);
213 
214  const auto& ret_ti = function_oper->get_type_info();
215  CHECK(ret_ti.is_integer() || ret_ti.is_fp() || ret_ti.is_boolean() ||
216  ret_ti.is_array());
217  if (ret_ti.is_array() && co.device_type == ExecutorDeviceType::GPU) {
218  throw QueryMustRunOnCpu();
219  }
220  auto ret_ty = ext_arg_type_to_llvm_type(ext_func_sig.getRet(), cgen_state_->context_);
221  const auto current_bb = cgen_state_->ir_builder_.GetInsertBlock();
222  for (auto it : cgen_state_->ext_call_cache_) {
223  if (*it.foper == *function_oper) {
224  auto inst = llvm::dyn_cast<llvm::Instruction>(it.lv);
225  if (inst && inst->getParent() == current_bb) {
226  return it.lv;
227  }
228  }
229  }
230  std::vector<llvm::Value*> orig_arg_lvs;
231  std::unordered_map<llvm::Value*, llvm::Value*> const_arr_size;
232  for (size_t i = 0; i < function_oper->getArity(); ++i) {
233  const auto arg = function_oper->getArg(i);
234  const auto arg_cast = dynamic_cast<const Analyzer::UOper*>(arg);
235  const auto arg0 =
236  (arg_cast && arg_cast->get_optype() == kCAST) ? arg_cast->get_operand() : arg;
237  const auto array_expr_arg = dynamic_cast<const Analyzer::ArrayExpr*>(arg0);
238  auto is_local_alloc =
239  ret_ti.is_array() || (array_expr_arg && array_expr_arg->isLocalAlloc());
240  const auto& arg_ti = arg->get_type_info();
241  const auto arg_lvs = codegen(arg, true, co);
242  auto geo_uoper_arg = dynamic_cast<const Analyzer::GeoUOper*>(arg);
243  auto geo_binoper_arg = dynamic_cast<const Analyzer::GeoBinOper*>(arg);
244  // TODO(adb / d): Assuming no const array cols for geo (for now)
245  if ((geo_uoper_arg || geo_binoper_arg) && arg_ti.is_geometry()) {
246  // Extract arr sizes and put them in the map, forward arr pointers
247  CHECK_EQ(2 * static_cast<size_t>(arg_ti.get_physical_coord_cols()), arg_lvs.size());
248  for (size_t i = 0; i < arg_lvs.size(); i++) {
249  auto arr = arg_lvs[i++];
250  auto size = arg_lvs[i];
251  orig_arg_lvs.push_back(arr);
252  const_arr_size[arr] = size;
253  }
254  } else if (arg_ti.is_geometry()) {
255  CHECK_EQ(static_cast<size_t>(arg_ti.get_physical_coord_cols()), arg_lvs.size());
256  for (size_t j = 0; j < arg_lvs.size(); j++) {
257  orig_arg_lvs.push_back(arg_lvs[j]);
258  }
259  } else {
260  if (arg_lvs.size() > 1) {
261  CHECK(arg_ti.is_array());
262  CHECK_EQ(size_t(2), arg_lvs.size());
263  const_arr_size[arg_lvs.front()] = arg_lvs.back();
264  } else {
265  CHECK_EQ(size_t(1), arg_lvs.size());
266  if (is_local_alloc && arg_ti.get_size() > 0) {
267  const_arr_size[arg_lvs.front()] = cgen_state_->llInt(arg_ti.get_size());
268  }
269  }
270  orig_arg_lvs.push_back(arg_lvs.front());
271  }
272  }
273  // The extension function implementations don't handle NULL, they work under
274  // the assumption that the inputs are validated before calling them. Generate
275  // code to do the check at the call site: if any argument is NULL, return NULL
276  // without calling the function at all.
277  const auto [bbs, null_array_ptr] = beginArgsNullcheck(function_oper, orig_arg_lvs);
278  CHECK_GE(orig_arg_lvs.size(), function_oper->getArity());
279  // Arguments must be converted to the types the extension function can handle.
281  function_oper, &ext_func_sig, orig_arg_lvs, const_arr_size, co);
282 
283  llvm::Value* array_ret{nullptr};
284  if (ret_ti.is_array()) {
285  // codegen array return as first arg
286  ret_ty = llvm::Type::getVoidTy(cgen_state_->context_);
287  const auto arr_struct_ty = get_arr_struct_type(
288  cgen_state_,
289  function_oper->getName(),
291  0);
292  array_ret = cgen_state_->ir_builder_.CreateAlloca(arr_struct_ty);
293  args.insert(args.begin(), array_ret);
294  }
295  const auto ext_call = cgen_state_->emitExternalCall(
296  ext_func_sig.getName(), ret_ty, args, {}, ret_ti.is_array());
297  auto ext_call_nullcheck = endArgsNullcheck(
298  bbs, ret_ti.is_array() ? array_ret : ext_call, null_array_ptr, function_oper);
299 
300  // Cast the return of the extension function to match the FunctionOper
301  if (!ret_ti.is_array()) {
302  const auto extension_ret_ti = get_sql_type_from_llvm_type(ret_ty);
303  if (bbs.args_null_bb &&
304  extension_ret_ti.get_type() != function_oper->get_type_info().get_type() &&
305  // Skip i1-->i8 casts for ST_ functions.
306  // function_oper ret type is i1, extension ret type is 'upgraded' to i8
307  // during type deserialization to 'handle' NULL returns, hence i1-->i8.
308  // ST_ functions can't return NULLs, we just need to check arg nullness
309  // and if any args are NULL then ST_ function is not called
310  function_oper->getName().substr(0, 3) != std::string("ST_")) {
311  ext_call_nullcheck = codegenCast(ext_call_nullcheck,
312  extension_ret_ti,
313  function_oper->get_type_info(),
314  false,
315  co);
316  }
317  }
318 
319  cgen_state_->ext_call_cache_.push_back({function_oper, ext_call_nullcheck});
320 
321  return ext_call_nullcheck;
322 }
323 
324 // Start the control flow needed for a call site check of NULL arguments.
325 std::tuple<CodeGenerator::ArgNullcheckBBs, llvm::Value*>
327  const std::vector<llvm::Value*>& orig_arg_lvs) {
328  llvm::BasicBlock* args_null_bb{nullptr};
329  llvm::BasicBlock* args_notnull_bb{nullptr};
330  llvm::BasicBlock* orig_bb = cgen_state_->ir_builder_.GetInsertBlock();
331  llvm::Value* null_array_alloca{nullptr};
332  // Only generate the check if required (at least one argument must be nullable).
333  if (ext_func_call_requires_nullcheck(function_oper)) {
334  if (function_oper->get_type_info().is_array()) {
335  const auto arr_struct_ty =
337  function_oper->getName(),
339  function_oper->get_type_info(), cgen_state_->context_),
340  0);
341  null_array_alloca = cgen_state_->ir_builder_.CreateAlloca(arr_struct_ty);
342  }
343  const auto args_notnull_lv = cgen_state_->ir_builder_.CreateNot(
344  codegenFunctionOperNullArg(function_oper, orig_arg_lvs));
345  args_notnull_bb = llvm::BasicBlock::Create(
346  cgen_state_->context_, "args_notnull", cgen_state_->row_func_);
347  args_null_bb = llvm::BasicBlock::Create(
348  cgen_state_->context_, "args_null", cgen_state_->row_func_);
349  cgen_state_->ir_builder_.CreateCondBr(args_notnull_lv, args_notnull_bb, args_null_bb);
350  cgen_state_->ir_builder_.SetInsertPoint(args_notnull_bb);
351  }
352  return std::make_tuple(
353  CodeGenerator::ArgNullcheckBBs{args_null_bb, args_notnull_bb, orig_bb},
354  null_array_alloca);
355 }
356 
357 // Wrap up the control flow needed for NULL argument handling.
359  const ArgNullcheckBBs& bbs,
360  llvm::Value* fn_ret_lv,
361  llvm::Value* null_array_ptr,
362  const Analyzer::FunctionOper* function_oper) {
363  if (bbs.args_null_bb) {
364  CHECK(bbs.args_notnull_bb);
365  cgen_state_->ir_builder_.CreateBr(bbs.args_null_bb);
366  cgen_state_->ir_builder_.SetInsertPoint(bbs.args_null_bb);
367 
368  llvm::PHINode* ext_call_phi{nullptr};
369  llvm::Value* null_lv{nullptr};
370  if (!function_oper->get_type_info().is_array()) {
371  // The pre-cast SQL equivalent of the type returned by the extension function.
372  const auto extension_ret_ti = get_sql_type_from_llvm_type(fn_ret_lv->getType());
373 
374  ext_call_phi = cgen_state_->ir_builder_.CreatePHI(
375  extension_ret_ti.is_fp()
376  ? get_fp_type(extension_ret_ti.get_size() * 8, cgen_state_->context_)
377  : get_int_type(extension_ret_ti.get_size() * 8, cgen_state_->context_),
378  2);
379 
380  null_lv =
381  extension_ret_ti.is_fp()
382  ? static_cast<llvm::Value*>(cgen_state_->inlineFpNull(extension_ret_ti))
383  : static_cast<llvm::Value*>(cgen_state_->inlineIntNull(extension_ret_ti));
384  } else {
385  const auto arr_struct_ty =
387  function_oper->getName(),
389  function_oper->get_type_info(), cgen_state_->context_),
390  0);
391  ext_call_phi =
392  cgen_state_->ir_builder_.CreatePHI(llvm::PointerType::get(arr_struct_ty, 0), 2);
393 
394  CHECK(null_array_ptr);
395  const auto arr_null_bool =
396  cgen_state_->ir_builder_.CreateStructGEP(arr_struct_ty, null_array_ptr, 2);
397  cgen_state_->ir_builder_.CreateStore(
398  llvm::ConstantInt::get(get_int_type(1, cgen_state_->context_), 1),
399  arr_null_bool);
400 
401  const auto arr_null_size =
402  cgen_state_->ir_builder_.CreateStructGEP(arr_struct_ty, null_array_ptr, 1);
403  cgen_state_->ir_builder_.CreateStore(
404  llvm::ConstantInt::get(get_int_type(64, cgen_state_->context_), 0),
405  arr_null_size);
406  }
407  ext_call_phi->addIncoming(fn_ret_lv, bbs.args_notnull_bb);
408  ext_call_phi->addIncoming(
409  function_oper->get_type_info().is_array() ? null_array_ptr : null_lv,
410  bbs.orig_bb);
411 
412  return ext_call_phi;
413  }
414  return fn_ret_lv;
415 }
416 
417 namespace {
418 
420  const auto& ret_ti = function_oper->get_type_info();
421  if (!ret_ti.is_integer() && !ret_ti.is_fp()) {
422  return true;
423  }
424  for (size_t i = 0; i < function_oper->getArity(); ++i) {
425  const auto arg = function_oper->getArg(i);
426  const auto& arg_ti = arg->get_type_info();
427  if (!arg_ti.is_integer() && !arg_ti.is_fp()) {
428  return true;
429  }
430  }
431  return false;
432 }
433 
434 } // namespace
435 
438  const CompilationOptions& co) {
439  if (call_requires_custom_type_handling(function_oper)) {
440  // Some functions need the return type to be the same as the input type.
441  if (function_oper->getName() == "FLOOR" || function_oper->getName() == "CEIL") {
442  CHECK_EQ(size_t(1), function_oper->getArity());
443  const auto arg = function_oper->getArg(0);
444  const auto& arg_ti = arg->get_type_info();
445  CHECK(arg_ti.is_decimal());
446  const auto arg_lvs = codegen(arg, true, co);
447  CHECK_EQ(size_t(1), arg_lvs.size());
448  const auto arg_lv = arg_lvs.front();
449  CHECK(arg_lv->getType()->isIntegerTy(64));
451  std::tie(bbs, std::ignore) = beginArgsNullcheck(function_oper, {arg_lvs});
452  const std::string func_name =
453  (function_oper->getName() == "FLOOR") ? "decimal_floor" : "decimal_ceil";
454  const auto covar_result_lv = cgen_state_->emitCall(
455  func_name, {arg_lv, cgen_state_->llInt(exp_to_scale(arg_ti.get_scale()))});
456  const auto ret_ti = function_oper->get_type_info();
457  CHECK(ret_ti.is_decimal());
458  CHECK_EQ(0, ret_ti.get_scale());
459  const auto result_lv = cgen_state_->ir_builder_.CreateSDiv(
460  covar_result_lv, cgen_state_->llInt(exp_to_scale(arg_ti.get_scale())));
461  return endArgsNullcheck(bbs, result_lv, nullptr, function_oper);
462  } else if (function_oper->getName() == "ROUND" &&
463  function_oper->getArg(0)->get_type_info().is_decimal()) {
464  CHECK_EQ(size_t(2), function_oper->getArity());
465 
466  const auto arg0 = function_oper->getArg(0);
467  const auto& arg0_ti = arg0->get_type_info();
468  const auto arg0_lvs = codegen(arg0, true, co);
469  CHECK_EQ(size_t(1), arg0_lvs.size());
470  const auto arg0_lv = arg0_lvs.front();
471  CHECK(arg0_lv->getType()->isIntegerTy(64));
472 
473  const auto arg1 = function_oper->getArg(1);
474  const auto& arg1_ti = arg1->get_type_info();
475  CHECK(arg1_ti.is_integer());
476  const auto arg1_lvs = codegen(arg1, true, co);
477  auto arg1_lv = arg1_lvs.front();
478  if (arg1_ti.get_type() != kINT) {
479  arg1_lv = codegenCast(arg1_lv, arg1_ti, SQLTypeInfo(kINT, true), false, co);
480  }
481 
483  std::tie(bbs0, std::ignore) =
484  beginArgsNullcheck(function_oper, {arg0_lv, arg1_lvs.front()});
485 
486  const std::string func_name = "Round__4";
487  const auto ret_ti = function_oper->get_type_info();
488  CHECK(ret_ti.is_decimal());
489  const auto result_lv = cgen_state_->emitExternalCall(
490  func_name,
492  {arg0_lv, arg1_lv, cgen_state_->llInt(arg0_ti.get_scale())});
493 
494  return endArgsNullcheck(bbs0, result_lv, nullptr, function_oper);
495  }
496  throw std::runtime_error("Type combination not supported for function " +
497  function_oper->getName());
498  }
499  return codegenFunctionOper(function_oper, co);
500 }
501 
502 // Generates code which returns true iff at least one of the arguments is NULL.
504  const Analyzer::FunctionOper* function_oper,
505  const std::vector<llvm::Value*>& orig_arg_lvs) {
506  llvm::Value* one_arg_null =
507  llvm::ConstantInt::get(llvm::IntegerType::getInt1Ty(cgen_state_->context_), false);
508  size_t physical_coord_cols = 0;
509  for (size_t i = 0, j = 0; i < function_oper->getArity();
510  ++i, j += std::max(size_t(1), physical_coord_cols)) {
511  const auto arg = function_oper->getArg(i);
512  const auto& arg_ti = arg->get_type_info();
513  physical_coord_cols = arg_ti.get_physical_coord_cols();
514  if (arg_ti.get_notnull()) {
515  continue;
516  }
517 #ifdef ENABLE_GEOS
518  // If geo arg is coming from geos, skip the null check, assume it's a valid geo
519  if (arg_ti.is_geometry()) {
520  auto* coords_load = llvm::dyn_cast<llvm::LoadInst>(orig_arg_lvs[i]);
521  if (coords_load) {
522  continue;
523  }
524  }
525 #endif
526  if (arg_ti.is_array() || arg_ti.is_geometry()) {
527  // POINT [un]compressed coord check requires custom checker and chunk iterator
528  // Non-POINT NULL geographies will have a normally encoded null coord array
529  auto fname =
530  (arg_ti.get_type() == kPOINT) ? "point_coord_array_is_null" : "array_is_null";
531  auto is_null_lv = cgen_state_->emitExternalCall(
532  fname, get_int_type(1, cgen_state_->context_), {orig_arg_lvs[j], posArg(arg)});
533  one_arg_null = cgen_state_->ir_builder_.CreateOr(one_arg_null, is_null_lv);
534  continue;
535  }
536  CHECK(arg_ti.is_number());
537  one_arg_null = cgen_state_->ir_builder_.CreateOr(
538  one_arg_null, codegenIsNullNumber(orig_arg_lvs[j], arg_ti));
539  }
540  return one_arg_null;
541 }
542 
543 llvm::Value* CodeGenerator::codegenCompression(const SQLTypeInfo& type_info) {
544  int32_t compression = (type_info.get_compression() == kENCODING_GEOINT &&
545  type_info.get_comp_param() == 32)
546  ? 1
547  : 0;
548 
549  return cgen_state_->llInt(compression);
550 }
551 
552 std::pair<llvm::Value*, llvm::Value*> CodeGenerator::codegenArrayBuff(
553  llvm::Value* chunk,
554  llvm::Value* row_pos,
555  SQLTypes array_type,
556  bool cast_and_extend) {
557  const auto elem_ti =
558  SQLTypeInfo(
559  SQLTypes::kARRAY, 0, 0, false, EncodingType::kENCODING_NONE, 0, array_type)
560  .get_elem_type();
561 
562  auto buff = cgen_state_->emitExternalCall(
563  "array_buff", llvm::Type::getInt32PtrTy(cgen_state_->context_), {chunk, row_pos});
564 
565  auto len = cgen_state_->emitExternalCall(
566  "array_size",
567  get_int_type(32, cgen_state_->context_),
568  {chunk, row_pos, cgen_state_->llInt(log2_bytes(elem_ti.get_logical_size()))});
569 
570  if (cast_and_extend) {
571  buff = castArrayPointer(buff, elem_ti);
572  len =
573  cgen_state_->ir_builder_.CreateZExt(len, get_int_type(64, cgen_state_->context_));
574  }
575 
576  return std::make_pair(buff, len);
577 }
578 
579 void CodeGenerator::codegenArrayArgs(const std::string& ext_func_name,
580  size_t param_num,
581  llvm::Value* array_buf,
582  llvm::Value* array_size,
583  llvm::Value* array_null,
584  std::vector<llvm::Value*>& output_args) {
585  CHECK(array_buf);
586  CHECK(array_size);
587  CHECK(array_null);
588 
589  auto array_abstraction =
590  get_arr_struct_type(cgen_state_, ext_func_name, array_buf->getType(), param_num);
591  auto alloc_mem = cgen_state_->ir_builder_.CreateAlloca(array_abstraction);
592 
593  auto array_buf_ptr =
594  cgen_state_->ir_builder_.CreateStructGEP(array_abstraction, alloc_mem, 0);
595  cgen_state_->ir_builder_.CreateStore(array_buf, array_buf_ptr);
596 
597  auto array_size_ptr =
598  cgen_state_->ir_builder_.CreateStructGEP(array_abstraction, alloc_mem, 1);
599  cgen_state_->ir_builder_.CreateStore(array_size, array_size_ptr);
600 
601  auto bool_extended_type = llvm::Type::getInt8Ty(cgen_state_->context_);
602  auto array_null_extended =
603  cgen_state_->ir_builder_.CreateZExt(array_null, bool_extended_type);
604  auto array_is_null_ptr =
605  cgen_state_->ir_builder_.CreateStructGEP(array_abstraction, alloc_mem, 2);
606  cgen_state_->ir_builder_.CreateStore(array_null_extended, array_is_null_ptr);
607  output_args.push_back(alloc_mem);
608 }
609 
610 llvm::StructType* CodeGenerator::createPointStructType(const std::string& udf_func_name,
611  size_t param_num) {
612  llvm::Function* udf_func = cgen_state_->module_->getFunction(udf_func_name);
613  llvm::Module* module_for_lookup = cgen_state_->module_;
614 
615  CHECK(udf_func);
616 
617  llvm::FunctionType* udf_func_type = udf_func->getFunctionType();
618  CHECK(param_num < udf_func_type->getNumParams());
619  llvm::Type* param_type = udf_func_type->getParamType(param_num);
620  CHECK(param_type->isPointerTy());
621  llvm::Type* struct_type = param_type->getPointerElementType();
622  CHECK(struct_type->isStructTy());
623  CHECK(struct_type->getStructNumElements() == 5);
624 
625  llvm::StringRef struct_name = struct_type->getStructName();
626 
627  llvm::StructType* point_type = module_for_lookup->getTypeByName(struct_name);
628  CHECK(point_type);
629 
630  return (point_type);
631 }
632 
633 void CodeGenerator::codegenGeoPointArgs(const std::string& udf_func_name,
634  size_t param_num,
635  llvm::Value* point_buf,
636  llvm::Value* point_size,
637  llvm::Value* compression,
638  llvm::Value* input_srid,
639  llvm::Value* output_srid,
640  std::vector<llvm::Value*>& output_args) {
641  CHECK(point_buf);
642  CHECK(point_size);
643  CHECK(compression);
644  CHECK(input_srid);
645  CHECK(output_srid);
646 
647  auto point_abstraction = createPointStructType(udf_func_name, param_num);
648  auto alloc_mem = cgen_state_->ir_builder_.CreateAlloca(point_abstraction, nullptr);
649 
650  auto point_buf_ptr =
651  cgen_state_->ir_builder_.CreateStructGEP(point_abstraction, alloc_mem, 0);
652  cgen_state_->ir_builder_.CreateStore(point_buf, point_buf_ptr);
653 
654  auto point_size_ptr =
655  cgen_state_->ir_builder_.CreateStructGEP(point_abstraction, alloc_mem, 1);
656  cgen_state_->ir_builder_.CreateStore(point_size, point_size_ptr);
657 
658  auto point_compression_ptr =
659  cgen_state_->ir_builder_.CreateStructGEP(point_abstraction, alloc_mem, 2);
660  cgen_state_->ir_builder_.CreateStore(compression, point_compression_ptr);
661 
662  auto input_srid_ptr =
663  cgen_state_->ir_builder_.CreateStructGEP(point_abstraction, alloc_mem, 3);
664  cgen_state_->ir_builder_.CreateStore(input_srid, input_srid_ptr);
665 
666  auto output_srid_ptr =
667  cgen_state_->ir_builder_.CreateStructGEP(point_abstraction, alloc_mem, 4);
668  cgen_state_->ir_builder_.CreateStore(output_srid, output_srid_ptr);
669 
670  output_args.push_back(alloc_mem);
671 }
672 
674  const std::string& udf_func_name,
675  size_t param_num) {
676  llvm::Function* udf_func = cgen_state_->module_->getFunction(udf_func_name);
677  llvm::Module* module_for_lookup = cgen_state_->module_;
678 
679  CHECK(udf_func);
680 
681  llvm::FunctionType* udf_func_type = udf_func->getFunctionType();
682  CHECK(param_num < udf_func_type->getNumParams());
683  llvm::Type* param_type = udf_func_type->getParamType(param_num);
684  CHECK(param_type->isPointerTy());
685  llvm::Type* struct_type = param_type->getPointerElementType();
686  CHECK(struct_type->isStructTy());
687  CHECK(struct_type->getStructNumElements() == 5);
688 
689  llvm::StringRef struct_name = struct_type->getStructName();
690 
691  llvm::StructType* line_string_type = module_for_lookup->getTypeByName(struct_name);
692  CHECK(line_string_type);
693 
694  return (line_string_type);
695 }
696 
697 void CodeGenerator::codegenGeoLineStringArgs(const std::string& udf_func_name,
698  size_t param_num,
699  llvm::Value* line_string_buf,
700  llvm::Value* line_string_size,
701  llvm::Value* compression,
702  llvm::Value* input_srid,
703  llvm::Value* output_srid,
704  std::vector<llvm::Value*>& output_args) {
705  CHECK(line_string_buf);
706  CHECK(line_string_size);
707  CHECK(compression);
708  CHECK(input_srid);
709  CHECK(output_srid);
710 
711  auto line_string_abstraction = createLineStringStructType(udf_func_name, param_num);
712  auto alloc_mem =
713  cgen_state_->ir_builder_.CreateAlloca(line_string_abstraction, nullptr);
714 
715  auto line_string_buf_ptr =
716  cgen_state_->ir_builder_.CreateStructGEP(line_string_abstraction, alloc_mem, 0);
717  cgen_state_->ir_builder_.CreateStore(line_string_buf, line_string_buf_ptr);
718 
719  auto line_string_size_ptr =
720  cgen_state_->ir_builder_.CreateStructGEP(line_string_abstraction, alloc_mem, 1);
721  cgen_state_->ir_builder_.CreateStore(line_string_size, line_string_size_ptr);
722 
723  auto line_string_compression_ptr =
724  cgen_state_->ir_builder_.CreateStructGEP(line_string_abstraction, alloc_mem, 2);
725  cgen_state_->ir_builder_.CreateStore(compression, line_string_compression_ptr);
726 
727  auto input_srid_ptr =
728  cgen_state_->ir_builder_.CreateStructGEP(line_string_abstraction, alloc_mem, 3);
729  cgen_state_->ir_builder_.CreateStore(input_srid, input_srid_ptr);
730 
731  auto output_srid_ptr =
732  cgen_state_->ir_builder_.CreateStructGEP(line_string_abstraction, alloc_mem, 4);
733  cgen_state_->ir_builder_.CreateStore(output_srid, output_srid_ptr);
734 
735  output_args.push_back(alloc_mem);
736 }
737 
738 llvm::StructType* CodeGenerator::createPolygonStructType(const std::string& udf_func_name,
739  size_t param_num) {
740  llvm::Function* udf_func = cgen_state_->module_->getFunction(udf_func_name);
741  llvm::Module* module_for_lookup = cgen_state_->module_;
742 
743  CHECK(udf_func);
744 
745  llvm::FunctionType* udf_func_type = udf_func->getFunctionType();
746  CHECK(param_num < udf_func_type->getNumParams());
747  llvm::Type* param_type = udf_func_type->getParamType(param_num);
748  CHECK(param_type->isPointerTy());
749  llvm::Type* struct_type = param_type->getPointerElementType();
750  CHECK(struct_type->isStructTy());
751  CHECK(struct_type->getStructNumElements() == 7);
752 
753  llvm::StringRef struct_name = struct_type->getStructName();
754 
755  llvm::StructType* polygon_type = module_for_lookup->getTypeByName(struct_name);
756  CHECK(polygon_type);
757 
758  return (polygon_type);
759 }
760 
761 void CodeGenerator::codegenGeoPolygonArgs(const std::string& udf_func_name,
762  size_t param_num,
763  llvm::Value* polygon_buf,
764  llvm::Value* polygon_size,
765  llvm::Value* ring_sizes_buf,
766  llvm::Value* num_rings,
767  llvm::Value* compression,
768  llvm::Value* input_srid,
769  llvm::Value* output_srid,
770  std::vector<llvm::Value*>& output_args) {
771  CHECK(polygon_buf);
772  CHECK(polygon_size);
773  CHECK(ring_sizes_buf);
774  CHECK(num_rings);
775  CHECK(compression);
776  CHECK(input_srid);
777  CHECK(output_srid);
778 
779  auto polygon_abstraction = createPolygonStructType(udf_func_name, param_num);
780  auto alloc_mem = cgen_state_->ir_builder_.CreateAlloca(polygon_abstraction, nullptr);
781 
782  auto polygon_buf_ptr =
783  cgen_state_->ir_builder_.CreateStructGEP(polygon_abstraction, alloc_mem, 0);
784  cgen_state_->ir_builder_.CreateStore(polygon_buf, polygon_buf_ptr);
785 
786  auto polygon_size_ptr =
787  cgen_state_->ir_builder_.CreateStructGEP(polygon_abstraction, alloc_mem, 1);
788  cgen_state_->ir_builder_.CreateStore(polygon_size, polygon_size_ptr);
789 
790  auto ring_sizes_buf_ptr =
791  cgen_state_->ir_builder_.CreateStructGEP(polygon_abstraction, alloc_mem, 2);
792  cgen_state_->ir_builder_.CreateStore(ring_sizes_buf, ring_sizes_buf_ptr);
793 
794  auto ring_size_ptr =
795  cgen_state_->ir_builder_.CreateStructGEP(polygon_abstraction, alloc_mem, 3);
796  cgen_state_->ir_builder_.CreateStore(num_rings, ring_size_ptr);
797 
798  auto polygon_compression_ptr =
799  cgen_state_->ir_builder_.CreateStructGEP(polygon_abstraction, alloc_mem, 4);
800  cgen_state_->ir_builder_.CreateStore(compression, polygon_compression_ptr);
801 
802  auto input_srid_ptr =
803  cgen_state_->ir_builder_.CreateStructGEP(polygon_abstraction, alloc_mem, 5);
804  cgen_state_->ir_builder_.CreateStore(input_srid, input_srid_ptr);
805 
806  auto output_srid_ptr =
807  cgen_state_->ir_builder_.CreateStructGEP(polygon_abstraction, alloc_mem, 6);
808  cgen_state_->ir_builder_.CreateStore(output_srid, output_srid_ptr);
809 
810  output_args.push_back(alloc_mem);
811 }
812 
814  const std::string& udf_func_name,
815  size_t param_num) {
816  llvm::Function* udf_func = cgen_state_->module_->getFunction(udf_func_name);
817  llvm::Module* module_for_lookup = cgen_state_->module_;
818 
819  CHECK(udf_func);
820 
821  llvm::FunctionType* udf_func_type = udf_func->getFunctionType();
822  CHECK(param_num < udf_func_type->getNumParams());
823  llvm::Type* param_type = udf_func_type->getParamType(param_num);
824  CHECK(param_type->isPointerTy());
825  llvm::Type* struct_type = param_type->getPointerElementType();
826  CHECK(struct_type->isStructTy());
827  CHECK(struct_type->getStructNumElements() == 9);
828 
829  llvm::StringRef struct_name = struct_type->getStructName();
830 
831  llvm::StructType* polygon_type = module_for_lookup->getTypeByName(struct_name);
832  CHECK(polygon_type);
833 
834  return (polygon_type);
835 }
836 
837 void CodeGenerator::codegenGeoMultiPolygonArgs(const std::string& udf_func_name,
838  size_t param_num,
839  llvm::Value* polygon_coords,
840  llvm::Value* polygon_coords_size,
841  llvm::Value* ring_sizes_buf,
842  llvm::Value* ring_sizes,
843  llvm::Value* polygon_bounds,
844  llvm::Value* polygon_bounds_sizes,
845  llvm::Value* compression,
846  llvm::Value* input_srid,
847  llvm::Value* output_srid,
848  std::vector<llvm::Value*>& output_args) {
849  CHECK(polygon_coords);
850  CHECK(polygon_coords_size);
851  CHECK(ring_sizes_buf);
852  CHECK(ring_sizes);
853  CHECK(polygon_bounds);
854  CHECK(polygon_bounds_sizes);
855  CHECK(compression);
856  CHECK(input_srid);
857  CHECK(output_srid);
858 
859  auto multi_polygon_abstraction = createMultiPolygonStructType(udf_func_name, param_num);
860  auto alloc_mem =
861  cgen_state_->ir_builder_.CreateAlloca(multi_polygon_abstraction, nullptr);
862 
863  auto polygon_coords_ptr =
864  cgen_state_->ir_builder_.CreateStructGEP(multi_polygon_abstraction, alloc_mem, 0);
865  cgen_state_->ir_builder_.CreateStore(polygon_coords, polygon_coords_ptr);
866 
867  auto polygon_coords_size_ptr =
868  cgen_state_->ir_builder_.CreateStructGEP(multi_polygon_abstraction, alloc_mem, 1);
869  cgen_state_->ir_builder_.CreateStore(polygon_coords_size, polygon_coords_size_ptr);
870 
871  auto ring_sizes_buf_ptr =
872  cgen_state_->ir_builder_.CreateStructGEP(multi_polygon_abstraction, alloc_mem, 2);
873  cgen_state_->ir_builder_.CreateStore(ring_sizes_buf, ring_sizes_buf_ptr);
874 
875  auto ring_sizes_ptr =
876  cgen_state_->ir_builder_.CreateStructGEP(multi_polygon_abstraction, alloc_mem, 3);
877  cgen_state_->ir_builder_.CreateStore(ring_sizes, ring_sizes_ptr);
878 
879  auto polygon_bounds_buf_ptr =
880  cgen_state_->ir_builder_.CreateStructGEP(multi_polygon_abstraction, alloc_mem, 4);
881  cgen_state_->ir_builder_.CreateStore(polygon_bounds, polygon_bounds_buf_ptr);
882 
883  auto polygon_bounds_sizes_ptr =
884  cgen_state_->ir_builder_.CreateStructGEP(multi_polygon_abstraction, alloc_mem, 5);
885  cgen_state_->ir_builder_.CreateStore(polygon_bounds_sizes, polygon_bounds_sizes_ptr);
886 
887  auto polygon_compression_ptr =
888  cgen_state_->ir_builder_.CreateStructGEP(multi_polygon_abstraction, alloc_mem, 6);
889  cgen_state_->ir_builder_.CreateStore(compression, polygon_compression_ptr);
890 
891  auto input_srid_ptr =
892  cgen_state_->ir_builder_.CreateStructGEP(multi_polygon_abstraction, alloc_mem, 7);
893  cgen_state_->ir_builder_.CreateStore(input_srid, input_srid_ptr);
894 
895  auto output_srid_ptr =
896  cgen_state_->ir_builder_.CreateStructGEP(multi_polygon_abstraction, alloc_mem, 8);
897  cgen_state_->ir_builder_.CreateStore(output_srid, output_srid_ptr);
898 
899  output_args.push_back(alloc_mem);
900 }
901 
902 // Generate CAST operations for arguments in `orig_arg_lvs` to the types required by
903 // `ext_func_sig`.
905  const Analyzer::FunctionOper* function_oper,
906  const ExtensionFunction* ext_func_sig,
907  const std::vector<llvm::Value*>& orig_arg_lvs,
908  const std::unordered_map<llvm::Value*, llvm::Value*>& const_arr_size,
909  const CompilationOptions& co) {
910  CHECK(ext_func_sig);
911  const auto& ext_func_args = ext_func_sig->getArgs();
912  CHECK_LE(function_oper->getArity(), ext_func_args.size());
913  std::vector<llvm::Value*> args;
914  // i: argument in RA for the function op
915  // j: extra offset in orig_arg_lvs (to account for additional values required for a col,
916  // e.g. array cols) k: origin_arg_lvs counter
917  for (size_t i = 0, j = 0, k = 0; i < function_oper->getArity(); ++i, ++k) {
918  const auto arg = function_oper->getArg(i);
919  const auto& arg_ti = arg->get_type_info();
920  llvm::Value* arg_lv{nullptr};
921  if (arg_ti.is_array()) {
922  bool const_arr = (const_arr_size.count(orig_arg_lvs[k]) > 0);
923  const auto elem_ti = arg_ti.get_elem_type();
924  // TODO: switch to fast fixlen variants
925  const auto ptr_lv = (const_arr)
926  ? orig_arg_lvs[k]
928  "array_buff",
929  llvm::Type::getInt8PtrTy(cgen_state_->context_),
930  {orig_arg_lvs[k], posArg(arg)});
931  const auto len_lv =
932  (const_arr) ? const_arr_size.at(orig_arg_lvs[k])
934  "array_size",
936  {orig_arg_lvs[k],
937  posArg(arg),
938  cgen_state_->llInt(log2_bytes(elem_ti.get_logical_size()))});
939 
940  if (!is_ext_arg_type_array(ext_func_args[i])) {
941  args.push_back(castArrayPointer(ptr_lv, elem_ti));
942  args.push_back(cgen_state_->ir_builder_.CreateZExt(
943  len_lv, get_int_type(64, cgen_state_->context_)));
944  j++;
945  } else {
946  auto array_buf_arg = castArrayPointer(ptr_lv, elem_ti);
947  auto builder = cgen_state_->ir_builder_;
948  auto array_size_arg =
949  builder.CreateZExt(len_lv, get_int_type(64, cgen_state_->context_));
950  auto array_null_arg =
951  cgen_state_->emitExternalCall("array_is_null",
953  {orig_arg_lvs[k], posArg(arg)});
954  codegenArrayArgs(ext_func_sig->getName(),
955  function_oper->get_type_info().is_array() ? k + 1 : k,
956  array_buf_arg,
957  array_size_arg,
958  array_null_arg,
959  args);
960  }
961 
962  } else if (arg_ti.is_geometry()) {
963  // Coords
964  bool const_arr = (const_arr_size.count(orig_arg_lvs[k]) > 0);
965  // NOTE(adb): We're generating code to handle the TINYINT array only -- the actual
966  // geo encoding (or lack thereof) does not matter here
967  const auto elem_ti = SQLTypeInfo(SQLTypes::kARRAY,
968  0,
969  0,
970  false,
972  0,
974  .get_elem_type();
975  llvm::Value* ptr_lv;
976  llvm::Value* len_lv;
977  int32_t fixlen = -1;
978  if (arg_ti.get_type() == kPOINT) {
979  const auto col_var = dynamic_cast<const Analyzer::ColumnVar*>(arg);
980  if (col_var) {
981  const auto coords_cd = executor()->getPhysicalColumnDescriptor(col_var, 1);
982  if (coords_cd && coords_cd->columnType.get_type() == kARRAY) {
983  fixlen = coords_cd->columnType.get_size();
984  }
985  }
986  }
987  if (fixlen > 0) {
988  ptr_lv =
989  cgen_state_->emitExternalCall("fast_fixlen_array_buff",
990  llvm::Type::getInt8PtrTy(cgen_state_->context_),
991  {orig_arg_lvs[k], posArg(arg)});
992  len_lv = cgen_state_->llInt(int64_t(fixlen));
993  } else {
994  // TODO: remove const_arr and related code if it's not needed
995  ptr_lv = (const_arr) ? orig_arg_lvs[k]
997  "array_buff",
998  llvm::Type::getInt8PtrTy(cgen_state_->context_),
999  {orig_arg_lvs[k], posArg(arg)});
1000  len_lv = (const_arr)
1001  ? const_arr_size.at(orig_arg_lvs[k])
1003  "array_size",
1005  {orig_arg_lvs[k],
1006  posArg(arg),
1007  cgen_state_->llInt(log2_bytes(elem_ti.get_logical_size()))});
1008  }
1009 
1010  if (is_ext_arg_type_geo(ext_func_args[i])) {
1011  if (arg_ti.get_type() == kPOINT || arg_ti.get_type() == kLINESTRING) {
1012  auto array_buf_arg = castArrayPointer(ptr_lv, elem_ti);
1013  auto builder = cgen_state_->ir_builder_;
1014  auto array_size_arg =
1015  builder.CreateZExt(len_lv, get_int_type(64, cgen_state_->context_));
1016  auto compression_val = codegenCompression(arg_ti);
1017  auto input_srid_val = cgen_state_->llInt(arg_ti.get_input_srid());
1018  auto output_srid_val = cgen_state_->llInt(arg_ti.get_output_srid());
1019 
1020  if (arg_ti.get_type() == kPOINT) {
1021  codegenGeoPointArgs(ext_func_sig->getName(),
1022  k,
1023  array_buf_arg,
1024  array_size_arg,
1025  compression_val,
1026  input_srid_val,
1027  output_srid_val,
1028  args);
1029  } else {
1030  codegenGeoLineStringArgs(ext_func_sig->getName(),
1031  k,
1032  array_buf_arg,
1033  array_size_arg,
1034  compression_val,
1035  input_srid_val,
1036  output_srid_val,
1037  args);
1038  }
1039  }
1040  } else {
1041  args.push_back(castArrayPointer(ptr_lv, elem_ti));
1042  args.push_back(cgen_state_->ir_builder_.CreateZExt(
1043  len_lv, get_int_type(64, cgen_state_->context_)));
1044  j++;
1045  }
1046 
1047  switch (arg_ti.get_type()) {
1048  case kPOINT:
1049  case kLINESTRING:
1050  break;
1051  case kPOLYGON: {
1052  if (ext_func_args[i] == ExtArgumentType::GeoPolygon) {
1053  auto array_buf_arg = castArrayPointer(ptr_lv, elem_ti);
1054  auto builder = cgen_state_->ir_builder_;
1055  auto array_size_arg =
1056  builder.CreateZExt(len_lv, get_int_type(64, cgen_state_->context_));
1057  auto compression_val = codegenCompression(arg_ti);
1058  auto input_srid_val = cgen_state_->llInt(arg_ti.get_input_srid());
1059  auto output_srid_val = cgen_state_->llInt(arg_ti.get_output_srid());
1060 
1061  auto [ring_size_buff, ring_size] =
1062  codegenArrayBuff(orig_arg_lvs[k + 1], posArg(arg), SQLTypes::kINT, true);
1063 
1064  codegenGeoPolygonArgs(ext_func_sig->getName(),
1065  k,
1066  array_buf_arg,
1067  array_size_arg,
1068  ring_size_buff,
1069  ring_size,
1070  compression_val,
1071  input_srid_val,
1072  output_srid_val,
1073  args);
1074  k++;
1075  } else {
1076  k++;
1077  // Ring Sizes
1078  auto const_arr = const_arr_size.count(orig_arg_lvs[k]) > 0;
1079  auto [ring_size_buff, ring_size] =
1080  (const_arr)
1081  ? std::make_pair(orig_arg_lvs[k], const_arr_size.at(orig_arg_lvs[k]))
1082  : codegenArrayBuff(
1083  orig_arg_lvs[k], posArg(arg), SQLTypes::kINT, true);
1084  args.push_back(ring_size_buff);
1085  args.push_back(ring_size);
1086  j++;
1087  }
1088  break;
1089  }
1090  case kMULTIPOLYGON: {
1091  if (ext_func_args[i] == ExtArgumentType::GeoMultiPolygon) {
1092  auto array_buf_arg = castArrayPointer(ptr_lv, elem_ti);
1093  auto builder = cgen_state_->ir_builder_;
1094  auto array_size_arg =
1095  builder.CreateZExt(len_lv, get_int_type(64, cgen_state_->context_));
1096  auto compression_val = codegenCompression(arg_ti);
1097  auto input_srid_val = cgen_state_->llInt(arg_ti.get_input_srid());
1098  auto output_srid_val = cgen_state_->llInt(arg_ti.get_output_srid());
1099 
1100  auto [ring_size_buff, ring_size] =
1101  codegenArrayBuff(orig_arg_lvs[k + 1], posArg(arg), SQLTypes::kINT, true);
1102 
1103  auto [poly_bounds_buff, poly_bounds_size] =
1104  codegenArrayBuff(orig_arg_lvs[k + 2], posArg(arg), SQLTypes::kINT, true);
1105 
1106  codegenGeoMultiPolygonArgs(ext_func_sig->getName(),
1107  k,
1108  array_buf_arg,
1109  array_size_arg,
1110  ring_size_buff,
1111  ring_size,
1112  poly_bounds_buff,
1113  poly_bounds_size,
1114  compression_val,
1115  input_srid_val,
1116  output_srid_val,
1117  args);
1118 
1119  k += 2;
1120  } else {
1121  k++;
1122  // Ring Sizes
1123  {
1124  auto const_arr = const_arr_size.count(orig_arg_lvs[k]) > 0;
1125  auto [ring_size_buff, ring_size] =
1126  (const_arr) ? std::make_pair(orig_arg_lvs[k],
1127  const_arr_size.at(orig_arg_lvs[k]))
1128  : codegenArrayBuff(
1129  orig_arg_lvs[k], posArg(arg), SQLTypes::kINT, true);
1130 
1131  args.push_back(ring_size_buff);
1132  args.push_back(ring_size);
1133  }
1134  j++, k++;
1135 
1136  // Poly Rings
1137  {
1138  auto const_arr = const_arr_size.count(orig_arg_lvs[k]) > 0;
1139  auto [poly_bounds_buff, poly_bounds_size] =
1140  (const_arr) ? std::make_pair(orig_arg_lvs[k],
1141  const_arr_size.at(orig_arg_lvs[k]))
1142  : codegenArrayBuff(
1143  orig_arg_lvs[k], posArg(arg), SQLTypes::kINT, true);
1144 
1145  args.push_back(poly_bounds_buff);
1146  args.push_back(poly_bounds_size);
1147  }
1148  j++;
1149  }
1150  break;
1151  }
1152  default:
1153  CHECK(false);
1154  }
1155  } else {
1156  const auto arg_target_ti = ext_arg_type_to_type_info(ext_func_args[k + j]);
1157  if (arg_ti.get_type() != arg_target_ti.get_type()) {
1158  arg_lv = codegenCast(orig_arg_lvs[k], arg_ti, arg_target_ti, false, co);
1159  } else {
1160  arg_lv = orig_arg_lvs[k];
1161  }
1162  CHECK_EQ(arg_lv->getType(),
1163  ext_arg_type_to_llvm_type(ext_func_args[k + j], cgen_state_->context_));
1164  args.push_back(arg_lv);
1165  }
1166  }
1167  return args;
1168 }
1169 
1170 llvm::Value* CodeGenerator::castArrayPointer(llvm::Value* ptr,
1171  const SQLTypeInfo& elem_ti) {
1172  if (elem_ti.get_type() == kFLOAT) {
1173  return cgen_state_->ir_builder_.CreatePointerCast(
1174  ptr, llvm::Type::getFloatPtrTy(cgen_state_->context_));
1175  }
1176  if (elem_ti.get_type() == kDOUBLE) {
1177  return cgen_state_->ir_builder_.CreatePointerCast(
1178  ptr, llvm::Type::getDoublePtrTy(cgen_state_->context_));
1179  }
1180  CHECK(elem_ti.is_integer() || elem_ti.is_boolean() ||
1181  (elem_ti.is_string() && elem_ti.get_compression() == kENCODING_DICT));
1182  switch (elem_ti.get_size()) {
1183  case 1:
1184  return cgen_state_->ir_builder_.CreatePointerCast(
1185  ptr, llvm::Type::getInt8PtrTy(cgen_state_->context_));
1186  case 2:
1187  return cgen_state_->ir_builder_.CreatePointerCast(
1188  ptr, llvm::Type::getInt16PtrTy(cgen_state_->context_));
1189  case 4:
1190  return cgen_state_->ir_builder_.CreatePointerCast(
1191  ptr, llvm::Type::getInt32PtrTy(cgen_state_->context_));
1192  case 8:
1193  return cgen_state_->ir_builder_.CreatePointerCast(
1194  ptr, llvm::Type::getInt64PtrTy(cgen_state_->context_));
1195  default:
1196  CHECK(false);
1197  }
1198  return nullptr;
1199 }
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:205
HOST DEVICE int get_size() const
Definition: sqltypes.h:268
const std::vector< ExtArgumentType > & getArgs() const
const std::string & getName() const
llvm::BasicBlock * args_notnull_bb
size_t getArity() const
Definition: Analyzer.h:1361
SQLTypes
Definition: sqltypes.h:39
std::unique_ptr< llvm::Module > udf_gpu_module
bool is_ext_arg_type_geo(const ExtArgumentType ext_arg_type)
CgenState * cgen_state_
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)
std::vector< llvm::Value * > codegenFunctionOperCastArgs(const Analyzer::FunctionOper *, const ExtensionFunction *, const std::vector< llvm::Value * > &, const std::unordered_map< llvm::Value *, llvm::Value * > &, const CompilationOptions &)
#define LOG(tag)
Definition: Logger.h:188
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:206
ExtensionFunction bind_function(std::string name, Analyzer::ExpressionPtrVector func_args, const std::vector< ExtensionFunction > &ext_funcs)
llvm::Value * codegenFunctionOperNullArg(const Analyzer::FunctionOper *, const std::vector< llvm::Value * > &)
llvm::IRBuilder ir_builder_
Definition: CgenState.h:319
llvm::Value * posArg(const Analyzer::Expr *) const
Definition: ColumnIR.cpp:509
llvm::Value * castArrayPointer(llvm::Value *ptr, const SQLTypeInfo &elem_ti)
#define UNREACHABLE()
Definition: Logger.h:241
#define CHECK_GE(x, y)
Definition: Logger.h:210
Definition: sqldefs.h:49
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)
HOST DEVICE SQLTypes get_type() const
Definition: sqltypes.h:258
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:325
llvm::StructType * get_arr_struct_type(CgenState *cgen_state, const std::string &ext_func_name, llvm::Type *array_type, size_t param_num)
llvm::Function * row_func_
Definition: CgenState.h:315
std::pair< llvm::Value *, llvm::Value * > codegenArrayBuff(llvm::Value *chunk, llvm::Value *row_pos, SQLTypes array_type, bool cast_and_extend)
false auto cgen_state
void codegenArrayArgs(const std::string &udf_func_name, size_t param_num, llvm::Value *array_buf, llvm::Value *array_size, llvm::Value *array_is_null, std::vector< llvm::Value * > &output_args)
llvm::Module * module_
Definition: CgenState.h:314
llvm::LLVMContext & context_
Definition: CgenState.h:317
std::tuple< ArgNullcheckBBs, llvm::Value * > beginArgsNullcheck(const Analyzer::FunctionOper *function_oper, const std::vector< llvm::Value * > &orig_arg_lvs)
CHECK(cgen_state)
bool is_integer() const
Definition: sqltypes.h:417
llvm::ConstantInt * inlineIntNull(const SQLTypeInfo &)
Definition: CgenState.cpp:27
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:422
llvm::BasicBlock * args_null_bb
llvm::Type * ext_arg_type_to_llvm_type(const ExtArgumentType ext_arg_type, llvm::LLVMContext &ctx)
const SQLTypeInfo & get_type_info() const
Definition: Analyzer.h:79
llvm::Value * emitCall(const std::string &fname, const std::vector< llvm::Value * > &args)
Definition: CgenState.cpp:137
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)
bool is_ext_arg_type_array(const ExtArgumentType ext_arg_type)
std::vector< llvm::Value * > codegen(const Analyzer::Expr *, const bool fetch_columns, const CompilationOptions &)
Definition: IRCodegen.cpp:26
#define CHECK_LE(x, y)
Definition: Logger.h:208
HOST DEVICE EncodingType get_compression() const
Definition: sqltypes.h:266
std::string serialize_llvm_object(const T *llvm_obj)
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:1363
const Expr * get_operand() const
Definition: Analyzer.h:372
llvm::Value * endArgsNullcheck(const ArgNullcheckBBs &, llvm::Value *, llvm::Value *, const Analyzer::FunctionOper *)
std::unique_ptr< llvm::Module > udf_cpu_module
HOST DEVICE int get_comp_param() const
Definition: sqltypes.h:267
llvm::Value * codegenFunctionOperWithCustomTypeHandling(const Analyzer::FunctionOperWithCustomTypeHandling *, const CompilationOptions &)
llvm::ConstantInt * llInt(const T v) const
Definition: CgenState.h:296
llvm::Value * codegenIsNullNumber(llvm::Value *, const SQLTypeInfo &)
Definition: LogicalIR.cpp:396
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:20
uint32_t log2_bytes(const uint32_t bytes)
Definition: Execute.h:105
Definition: sqltypes.h:46
bool is_string() const
Definition: sqltypes.h:415
std::string getName() const
Definition: Analyzer.h:1359
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)
SQLTypeInfo get_elem_type() const
Definition: sqltypes.h:622
bool is_decimal() const
Definition: sqltypes.h:418
int get_physical_coord_cols() const
Definition: sqltypes.h:294
void register_buffer_with_executor_rsm(int64_t exec, int8_t *buffer)
bool is_array() const
Definition: sqltypes.h:423
SQLTypeInfo ext_arg_type_to_type_info(const ExtArgumentType ext_arg_type)
llvm::ConstantFP * inlineFpNull(const SQLTypeInfo &)
Definition: CgenState.cpp:65
Executor * executor() const
llvm::StructType * createMultiPolygonStructType(const std::string &udf_func_name, size_t param_num)