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