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