OmniSciDB  6686921089
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Distance.h
Go to the documentation of this file.
1 /*
2  * Copyright 2021 OmniSci, 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 #pragma once
18 
20 
21 namespace spatial_type {
22 
23 class Distance : public Codegen {
24  public:
25  Distance(const Analyzer::GeoOperator* geo_operator,
26  const Catalog_Namespace::Catalog* catalog)
27  : Codegen(geo_operator, catalog) {
28  CHECK_EQ(operator_->size(), size_t(2));
29  const auto& ti = operator_->get_type_info();
30  is_nullable_ = !ti.get_notnull();
31  }
32 
33  size_t size() const final { return 2; }
34 
36 
37  std::tuple<std::vector<llvm::Value*>, llvm::Value*> codegenLoads(
38  const std::vector<llvm::Value*>& arg_lvs,
39  const std::vector<llvm::Value*>& pos_lvs,
40  CgenState* cgen_state) final {
41  CHECK_EQ(pos_lvs.size(), size());
42  std::string size_fn_name = "array_size";
43  if (is_nullable_) {
44  size_fn_name += "_nullable";
45  }
46 
47  auto& builder = cgen_state->ir_builder_;
48  llvm::Value* is_null = cgen_state->llBool(false);
49 
50  std::vector<llvm::Value*> operand_lvs;
51  size_t arg_lvs_index{0};
52  for (size_t i = 0; i < size(); i++) {
53  const auto operand = getOperand(i);
54  CHECK(operand);
55  const auto& operand_ti = operand->get_type_info();
56  CHECK(IS_GEO(operand_ti.get_type()));
57  const size_t num_physical_coord_lvs = operand_ti.get_physical_coord_cols();
58 
59  // iterate over column inputs
60  bool is_coords_lv{true};
61  if (dynamic_cast<const Analyzer::ColumnVar*>(operand)) {
62  for (size_t j = 0; j < num_physical_coord_lvs; j++) {
63  CHECK_LT(arg_lvs_index, arg_lvs.size());
64  auto lv = arg_lvs[arg_lvs_index++];
65  // TODO: fast fixlen array buff for coords
66  auto array_buff_lv =
67  cgen_state->emitExternalCall("array_buff",
68  llvm::Type::getInt8PtrTy(cgen_state->context_),
69  {lv, pos_lvs[i]});
70  if (j > 0) {
71  // cast additional columns to i32*
72  array_buff_lv = builder.CreateBitCast(
73  array_buff_lv, llvm::Type::getInt32PtrTy(cgen_state->context_));
74  }
75  operand_lvs.push_back(array_buff_lv);
76 
77  const auto ptr_type = llvm::dyn_cast_or_null<llvm::PointerType>(lv->getType());
78  CHECK(ptr_type);
79  const auto elem_type = ptr_type->getElementType();
80  CHECK(elem_type);
81  const uint32_t coords_elem_sz_bytes =
82  operand_ti.get_compression() == kENCODING_NONE &&
83  operand_ti.get_type() == kPOINT
84  ? 8
85  : 1;
86  std::vector<llvm::Value*> array_sz_args{
87  lv,
88  pos_lvs[i],
89  cgen_state->llInt(log2_bytes(j == 0 ? coords_elem_sz_bytes : 4))};
90  if (is_nullable_) { // TODO: should we do this for all arguments, or just
91  // coords?
92  array_sz_args.push_back(cgen_state->llInt(
93  static_cast<int32_t>(inline_int_null_value<int32_t>())));
94  }
95  operand_lvs.push_back(cgen_state->emitExternalCall(
96  size_fn_name, get_int_type(32, cgen_state->context_), array_sz_args));
97  llvm::Value* operand_is_null_lv{nullptr};
98  if (is_nullable_ && is_coords_lv) {
99  if (operand_ti.get_type() == kPOINT) {
100  operand_is_null_lv = cgen_state->emitExternalCall(
101  "point_coord_array_is_null",
102  llvm::Type::getInt1Ty(cgen_state->context_),
103  {lv, pos_lvs[i]});
104  } else {
105  operand_is_null_lv = builder.CreateICmpEQ(
106  operand_lvs.back(),
107  cgen_state->llInt(
108  static_cast<int32_t>(inline_int_null_value<int32_t>())));
109  }
110  is_null = builder.CreateOr(is_null, operand_is_null_lv);
111  }
112  is_coords_lv = false;
113  }
114  } else {
115  bool is_coords_lv{true};
116  for (size_t j = 0; j < num_physical_coord_lvs; j++) {
117  // ptr
118  CHECK_LT(arg_lvs_index, arg_lvs.size());
119  auto array_buff_lv = arg_lvs[arg_lvs_index++];
120  if (j == 0) {
121  // cast alloca to i8*
122  array_buff_lv = builder.CreateBitCast(
123  array_buff_lv, llvm::Type::getInt8PtrTy(cgen_state->context_));
124  } else {
125  // cast additional columns to i32*
126  array_buff_lv = builder.CreateBitCast(
127  array_buff_lv, llvm::Type::getInt32PtrTy(cgen_state->context_));
128  }
129  operand_lvs.push_back(array_buff_lv);
130  if (is_nullable_ && is_coords_lv) {
131  auto coords_array_type =
132  llvm::dyn_cast<llvm::PointerType>(operand_lvs.back()->getType());
133  CHECK(coords_array_type);
134  is_null = builder.CreateOr(
135  is_null,
136  builder.CreateICmpEQ(operand_lvs.back(),
137  llvm::ConstantPointerNull::get(coords_array_type)));
138  }
139  is_coords_lv = false;
140  CHECK_LT(arg_lvs_index, arg_lvs.size());
141  operand_lvs.push_back(arg_lvs[arg_lvs_index++]);
142  }
143  }
144  }
145  CHECK_EQ(arg_lvs_index, arg_lvs.size());
146 
147  // use the points array size argument for nullability
148  return std::make_tuple(operand_lvs, is_nullable_ ? is_null : nullptr);
149  }
150 
151  std::vector<llvm::Value*> codegen(const std::vector<llvm::Value*>& args,
152  CodeGenerator::NullCheckCodegen* nullcheck_codegen,
153  CgenState* cgen_state,
154  const CompilationOptions& co) final {
155  const auto& first_operand_ti = getOperand(0)->get_type_info();
156  const auto& second_operand_ti = getOperand(1)->get_type_info();
157 
158  const bool is_geodesic = first_operand_ti.get_subtype() == kGEOGRAPHY &&
159  first_operand_ti.get_output_srid() == 4326;
160 
161  if (is_geodesic && !((first_operand_ti.get_type() == kPOINT &&
162  second_operand_ti.get_type() == kPOINT) ||
163  (first_operand_ti.get_type() == kLINESTRING &&
164  second_operand_ti.get_type() == kPOINT) ||
165  (first_operand_ti.get_type() == kPOINT &&
166  second_operand_ti.get_type() == kLINESTRING))) {
167  throw std::runtime_error(getName() +
168  " currently doesn't accept non-POINT geographies");
169  }
170 
171  std::string func_name = getName() + suffix(first_operand_ti.get_type()) +
172  suffix(second_operand_ti.get_type());
173  if (is_geodesic) {
174  func_name += "_Geodesic";
175  }
176  auto& builder = cgen_state->ir_builder_;
177 
178  std::vector<llvm::Value*> operand_lvs;
179  for (size_t i = 0; i < args.size(); i += 2) {
180  operand_lvs.push_back(args[i]);
181  operand_lvs.push_back(
182  builder.CreateSExt(args[i + 1], llvm::Type::getInt64Ty(cgen_state->context_)));
183  }
184 
185  const auto& ret_ti = operator_->get_type_info();
186  // push back ic, isr, osr for now
187  operand_lvs.push_back(
188  cgen_state->llInt(Geospatial::get_compression_scheme(first_operand_ti))); // ic 1
189  operand_lvs.push_back(
190  cgen_state->llInt(first_operand_ti.get_input_srid())); // in srid 1
191  operand_lvs.push_back(cgen_state->llInt(
192  Geospatial::get_compression_scheme(second_operand_ti))); // ic 2
193  operand_lvs.push_back(
194  cgen_state->llInt(second_operand_ti.get_input_srid())); // in srid 2
195  const auto srid_override = operator_->getOutputSridOverride();
196  operand_lvs.push_back(
197  cgen_state->llInt(srid_override ? *srid_override : 0)); // out srid
198 
199  if (getName() == "ST_Distance" && first_operand_ti.get_subtype() != kGEOGRAPHY &&
200  (first_operand_ti.get_type() != kPOINT ||
201  second_operand_ti.get_type() != kPOINT)) {
202  operand_lvs.push_back(cgen_state->llFp(double(0.0)));
203  }
204 
205  CHECK(ret_ti.get_type() == kDOUBLE);
206  auto ret = cgen_state->emitExternalCall(
207  func_name, llvm::Type::getDoubleTy(cgen_state->context_), operand_lvs);
208  if (is_nullable_) {
209  CHECK(nullcheck_codegen);
210  ret = nullcheck_codegen->finalize(cgen_state->inlineFpNull(ret_ti), ret);
211  }
212  return {ret};
213  }
214 };
215 
216 } // namespace spatial_type
#define CHECK_EQ(x, y)
Definition: Logger.h:217
class for a per-database catalog. also includes metadata for the current database and the current use...
Definition: Catalog.h:111
#define const
int32_t get_compression_scheme(const SQLTypeInfo &ti)
Definition: Compression.cpp:23
llvm::Type * get_int_type(const int width, llvm::LLVMContext &context)
std::string suffix(SQLTypes type)
Definition: Codegen.cpp:68
std::tuple< std::vector< llvm::Value * >, llvm::Value * > codegenLoads(const std::vector< llvm::Value * > &arg_lvs, const std::vector< llvm::Value * > &pos_lvs, CgenState *cgen_state) final
Definition: Distance.h:37
CONSTEXPR DEVICE bool is_null(const T &value)
std::vector< llvm::Value * > codegen(const std::vector< llvm::Value * > &args, CodeGenerator::NullCheckCodegen *nullcheck_codegen, CgenState *cgen_state, const CompilationOptions &co) final
Definition: Distance.h:151
const SQLTypeInfo & get_type_info() const
Definition: Analyzer.h:77
#define CHECK_LT(x, y)
Definition: Logger.h:219
Distance(const Analyzer::GeoOperator *geo_operator, const Catalog_Namespace::Catalog *catalog)
Definition: Distance.h:25
const Analyzer::GeoOperator * operator_
Definition: Codegen.h:70
size_t size() const
Definition: Analyzer.cpp:3640
size_t size() const final
Definition: Distance.h:33
#define CHECK(condition)
Definition: Logger.h:209
virtual const Analyzer::Expr * getOperand(const size_t index)
Definition: Codegen.cpp:63
uint32_t log2_bytes(const uint32_t bytes)
Definition: Execute.h:174
#define IS_GEO(T)
Definition: sqltypes.h:251
SQLTypeInfo getNullType() const final
Definition: Distance.h:35