OmniSciDB  06b3bd477c
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
GeoIR.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2019 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 #include "CodeGenerator.h"
18 #include "Execute.h"
19 #include "Shared/geo_compression.h"
20 
21 std::vector<llvm::Value*> CodeGenerator::codegenGeoUOper(
22  const Analyzer::GeoUOper* geo_expr,
23  const CompilationOptions& co) {
26  throw QueryMustRunOnCpu();
27  }
28  }
29 
30  auto argument_list = codegenGeoArgs(geo_expr->getArgs0(), co);
31 
33  return argument_list;
34  }
35 
36 #ifndef ENABLE_GEOS
37  throw std::runtime_error("Geo operation requires GEOS support.");
38 #endif
39 
40  // Basic set of arguments is currently common to all Geos_* func invocations:
41  // op kind, type of the first geo arg0, geo arg0 components
42  std::string func = "Geos_Wkb"s;
43  if (geo_expr->getTypeInfo0().get_output_srid() !=
44  geo_expr->get_type_info().get_output_srid()) {
45  throw std::runtime_error("GEOS runtime doesn't support geometry transforms.");
46  }
47  // Prepend arg0 geo SQLType
48  argument_list.insert(
49  argument_list.begin(),
50  cgen_state_->llInt(static_cast<int>(geo_expr->getTypeInfo0().get_type())));
51  // Prepend geo expr op
52  argument_list.insert(argument_list.begin(),
53  cgen_state_->llInt(static_cast<int>(geo_expr->getOp())));
54  for (auto i = 3; i > geo_expr->getTypeInfo0().get_physical_coord_cols(); i--) {
55  argument_list.insert(argument_list.end(), cgen_state_->llInt(int64_t(0)));
56  argument_list.insert(argument_list.end(),
57  llvm::ConstantPointerNull::get(
58  llvm::Type::getInt32PtrTy(cgen_state_->context_, 0)));
59  }
60  // Append geo expr compression
61  argument_list.insert(
62  argument_list.end(),
63  cgen_state_->llInt(static_cast<int>(
65  // Append geo expr SRID
66  argument_list.insert(
67  argument_list.end(),
68  cgen_state_->llInt(static_cast<int>(geo_expr->getTypeInfo0().get_output_srid())));
69 
70  // Deal with unary geo predicates
73  return codegenGeosPredicateCall(func, argument_list, co);
74  }
75 
76  throw std::runtime_error("Unsupported unary geo operation.");
77  return {};
78 }
79 
80 std::vector<llvm::Value*> CodeGenerator::codegenGeoBinOper(
81  Analyzer::GeoBinOper const* geo_expr,
82  CompilationOptions const& co) {
84  throw QueryMustRunOnCpu();
85  }
86 #ifndef ENABLE_GEOS
87  throw std::runtime_error("Geo operation requires GEOS support.");
88 #endif
89 
90  auto argument_list = codegenGeoArgs(geo_expr->getArgs0(), co);
91 
92  // Basic set of arguments is currently common to all Geos_* func invocations:
93  // op kind, type of the first geo arg0, geo arg0 components
94  std::string func = "Geos_Wkb"s;
95  if (geo_expr->getTypeInfo0().get_output_srid() !=
96  geo_expr->get_type_info().get_output_srid()) {
97  throw std::runtime_error("GEOS runtime doesn't support geometry transforms.");
98  }
99  // Prepend arg0 geo SQLType
100  argument_list.insert(
101  argument_list.begin(),
102  cgen_state_->llInt(static_cast<int>(geo_expr->getTypeInfo0().get_type())));
103  // Prepend geo expr op
104  argument_list.insert(argument_list.begin(),
105  cgen_state_->llInt(static_cast<int>(geo_expr->getOp())));
106  for (auto i = 3; i > geo_expr->getTypeInfo0().get_physical_coord_cols(); i--) {
107  argument_list.insert(argument_list.end(), cgen_state_->llInt(int64_t(0)));
108  argument_list.insert(argument_list.end(),
109  llvm::ConstantPointerNull::get(
110  llvm::Type::getInt32PtrTy(cgen_state_->context_, 0)));
111  }
112  // Append geo expr compression
113  argument_list.insert(
114  argument_list.end(),
115  cgen_state_->llInt(static_cast<int>(
117  // Append geo expr SRID
118  argument_list.insert(
119  argument_list.end(),
120  cgen_state_->llInt(static_cast<int>(geo_expr->getTypeInfo0().get_output_srid())));
121 
122  auto arg1_list = codegenGeoArgs(geo_expr->getArgs1(), co);
123 
127  func += "_Wkb"s;
128  if (geo_expr->getTypeInfo1().get_output_srid() !=
129  geo_expr->get_type_info().get_output_srid()) {
130  throw std::runtime_error("GEOS runtime doesn't support geometry transforms.");
131  }
132  // Prepend arg1 geo SQLType
133  arg1_list.insert(
134  arg1_list.begin(),
135  cgen_state_->llInt(static_cast<int>(geo_expr->getTypeInfo1().get_type())));
136  for (auto i = 3; i > geo_expr->getTypeInfo1().get_physical_coord_cols(); i--) {
137  arg1_list.insert(arg1_list.end(), cgen_state_->llInt(int64_t(0)));
138  arg1_list.insert(arg1_list.end(),
139  llvm::ConstantPointerNull::get(
140  llvm::Type::getInt32PtrTy(cgen_state_->context_, 0)));
141  }
142  // Append geo expr compression
143  arg1_list.insert(arg1_list.end(),
144  cgen_state_->llInt(static_cast<int>(
146  // Append geo expr compression
147  arg1_list.insert(arg1_list.end(),
149  } else if (geo_expr->getOp() == Geo_namespace::GeoBase::GeoOp::kBUFFER) {
150  // Extra argument in this case is double
151  func += "_double"s;
152  } else {
153  throw std::runtime_error("Unsupported binary geo operation.");
154  }
155 
156  // Append arg1 to the list
157  argument_list.insert(argument_list.end(), arg1_list.begin(), arg1_list.end());
158 
159  return codegenGeosConstructorCall(func, argument_list, co);
160 }
161 
162 std::vector<llvm::Value*> CodeGenerator::codegenGeoArgs(
163  const std::vector<std::shared_ptr<Analyzer::Expr>>& geo_args,
164  const CompilationOptions& co) {
165  std::vector<llvm::Value*> argument_list;
166  bool coord_col = true;
167  for (const auto& geo_arg : geo_args) {
168  const auto arg = geo_arg.get();
169  const auto& arg_ti = arg->get_type_info();
170  const auto elem_ti = arg_ti.get_elem_type();
171  const auto arg_lvs = codegen(arg, true, co);
172  if (arg_ti.is_number()) {
173  argument_list.emplace_back(arg_lvs.front());
174  continue;
175  }
176  if (arg_ti.is_geometry()) {
177  argument_list.insert(argument_list.end(), arg_lvs.begin(), arg_lvs.end());
178  continue;
179  }
180  CHECK(arg_ti.is_array());
181  if (arg_lvs.size() > 1) {
182  CHECK_EQ(size_t(2), arg_lvs.size());
183  auto ptr_lv = arg_lvs.front();
184  if (coord_col) {
185  coord_col = false;
186  } else {
187  ptr_lv = cgen_state_->ir_builder_.CreatePointerCast(
188  ptr_lv, llvm::Type::getInt32PtrTy(cgen_state_->context_));
189  }
190  argument_list.emplace_back(ptr_lv);
191  auto cast_len_lv = cgen_state_->ir_builder_.CreateZExt(
192  arg_lvs.back(), get_int_type(64, cgen_state_->context_));
193  argument_list.emplace_back(cast_len_lv);
194  } else {
195  CHECK_EQ(size_t(1), arg_lvs.size());
196  if (arg_ti.get_size() > 0) {
197  argument_list.emplace_back(arg_lvs.front());
198  argument_list.emplace_back(cgen_state_->llInt<int64_t>(arg_ti.get_size()));
199  } else {
200  auto ptr_lv =
201  cgen_state_->emitExternalCall("array_buff",
202  llvm::Type::getInt8PtrTy(cgen_state_->context_),
203  {arg_lvs.front(), posArg(arg)});
204  if (coord_col) {
205  coord_col = false;
206  } else {
207  ptr_lv = cgen_state_->ir_builder_.CreatePointerCast(
208  ptr_lv, llvm::Type::getInt32PtrTy(cgen_state_->context_));
209  }
210  argument_list.emplace_back(ptr_lv);
211  const auto len_lv = cgen_state_->emitExternalCall(
212  "array_size",
214  {arg_lvs.front(),
215  posArg(arg),
216  cgen_state_->llInt(log2_bytes(elem_ti.get_logical_size()))});
217  auto cast_len_lv = cgen_state_->ir_builder_.CreateZExt(
218  len_lv, get_int_type(64, cgen_state_->context_));
219  argument_list.emplace_back(cast_len_lv);
220  }
221  }
222  }
223  return argument_list;
224 }
225 
226 std::vector<llvm::Value*> CodeGenerator::codegenGeosPredicateCall(
227  const std::string& func,
228  std::vector<llvm::Value*> argument_list,
229  const CompilationOptions& co) {
230  auto i8_type = get_int_type(8, cgen_state_->context_);
231  auto result = cgen_state_->ir_builder_.CreateAlloca(i8_type, nullptr, "result");
232  argument_list.emplace_back(result);
233 
234  // Generate call to GEOS wrapper
235  cgen_state_->needs_geos_ = true;
236  auto status_lv = cgen_state_->emitExternalCall(
237  func, llvm::Type::getInt1Ty(cgen_state_->context_), argument_list);
238  // Need to check the status and throw an error if this call has failed.
239  llvm::BasicBlock* geos_pred_ok_bb{nullptr};
240  llvm::BasicBlock* geos_pred_fail_bb{nullptr};
241  geos_pred_ok_bb = llvm::BasicBlock::Create(
242  cgen_state_->context_, "geos_pred_ok_bb", cgen_state_->row_func_);
243  geos_pred_fail_bb = llvm::BasicBlock::Create(
244  cgen_state_->context_, "geos_pred_fail_bb", cgen_state_->row_func_);
245  if (!status_lv) {
246  status_lv = cgen_state_->llBool(false);
247  }
248  cgen_state_->ir_builder_.CreateCondBr(status_lv, geos_pred_ok_bb, geos_pred_fail_bb);
249  cgen_state_->ir_builder_.SetInsertPoint(geos_pred_fail_bb);
252  cgen_state_->ir_builder_.SetInsertPoint(geos_pred_ok_bb);
253  auto res = cgen_state_->ir_builder_.CreateLoad(result);
254  return {res};
255 }
256 
258  const std::string& func,
259  std::vector<llvm::Value*> argument_list,
260  const CompilationOptions& co) {
261  // Create output buffer pointers, append pointers to output args to
262  auto i8_type = get_int_type(8, cgen_state_->context_);
263  auto i32_type = get_int_type(32, cgen_state_->context_);
264  auto i64_type = get_int_type(64, cgen_state_->context_);
265  auto pi8_type = llvm::PointerType::get(i8_type, 0);
266  auto pi32_type = llvm::PointerType::get(i32_type, 0);
267 
268  auto result_type =
269  cgen_state_->ir_builder_.CreateAlloca(i32_type, nullptr, "result_type");
270  auto result_coords =
271  cgen_state_->ir_builder_.CreateAlloca(pi8_type, nullptr, "result_coords");
272  auto result_coords_size =
273  cgen_state_->ir_builder_.CreateAlloca(i64_type, nullptr, "result_coords_size");
274  auto result_ring_sizes =
275  cgen_state_->ir_builder_.CreateAlloca(pi32_type, nullptr, "result_ring_sizes");
276  auto result_ring_sizes_size =
277  cgen_state_->ir_builder_.CreateAlloca(i64_type, nullptr, "result_ring_sizes_size");
278  auto result_poly_rings =
279  cgen_state_->ir_builder_.CreateAlloca(pi32_type, nullptr, "result_poly_rings");
280  auto result_poly_rings_size =
281  cgen_state_->ir_builder_.CreateAlloca(i64_type, nullptr, "result_poly_rings_size");
282 
283  argument_list.emplace_back(result_type);
284  argument_list.emplace_back(result_coords);
285  argument_list.emplace_back(result_coords_size);
286  argument_list.emplace_back(result_ring_sizes);
287  argument_list.emplace_back(result_ring_sizes_size);
288  argument_list.emplace_back(result_poly_rings);
289  argument_list.emplace_back(result_poly_rings_size);
290 
291  // Generate call to GEOS wrapper
292  cgen_state_->needs_geos_ = true;
293  auto status_lv = cgen_state_->emitExternalCall(
294  func, llvm::Type::getInt1Ty(cgen_state_->context_), argument_list);
295  // Need to check the status and throw an error if this call has failed.
296  llvm::BasicBlock* geos_ok_bb{nullptr};
297  llvm::BasicBlock* geos_fail_bb{nullptr};
298  geos_ok_bb = llvm::BasicBlock::Create(
299  cgen_state_->context_, "geos_ok_bb", cgen_state_->row_func_);
300  geos_fail_bb = llvm::BasicBlock::Create(
301  cgen_state_->context_, "geos_fail_bb", cgen_state_->row_func_);
302  if (!status_lv) {
303  status_lv = cgen_state_->llBool(false);
304  }
305  cgen_state_->ir_builder_.CreateCondBr(status_lv, geos_ok_bb, geos_fail_bb);
306  cgen_state_->ir_builder_.SetInsertPoint(geos_fail_bb);
309  cgen_state_->ir_builder_.SetInsertPoint(geos_ok_bb);
310 
311  // TODO: Currently forcing the output to MULTIPOLYGON, but need to handle
312  // other possible geometries that geos may return, e.g. a POINT, a LINESTRING
313  // Need to handle empty result, e.g. empty intersection.
314  // The type of result is returned in `result_type`
315 
316  // Load return values
317  auto buf1 = cgen_state_->ir_builder_.CreateLoad(result_coords);
318  auto buf1s = cgen_state_->ir_builder_.CreateLoad(result_coords_size);
319  auto buf2 = cgen_state_->ir_builder_.CreateLoad(result_ring_sizes);
320  auto buf2s = cgen_state_->ir_builder_.CreateLoad(result_ring_sizes_size);
321  auto buf3 = cgen_state_->ir_builder_.CreateLoad(result_poly_rings);
322  auto buf3s = cgen_state_->ir_builder_.CreateLoad(result_poly_rings_size);
323 
324  // generate register_buffer_with_executor_rsm() calls to register all output buffers
326  "register_buffer_with_executor_rsm",
327  llvm::Type::getVoidTy(cgen_state_->context_),
328  {cgen_state_->llInt(reinterpret_cast<int64_t>(executor())),
329  cgen_state_->ir_builder_.CreatePointerCast(buf1, pi8_type)});
330  cgen_state_->emitExternalCall(
331  "register_buffer_with_executor_rsm",
332  llvm::Type::getVoidTy(cgen_state_->context_),
333  {cgen_state_->llInt(reinterpret_cast<int64_t>(executor())),
334  cgen_state_->ir_builder_.CreatePointerCast(buf2, pi8_type)});
335  cgen_state_->emitExternalCall(
336  "register_buffer_with_executor_rsm",
337  llvm::Type::getVoidTy(cgen_state_->context_),
338  {cgen_state_->llInt(reinterpret_cast<int64_t>(executor())),
339  cgen_state_->ir_builder_.CreatePointerCast(buf3, pi8_type)});
340 
341  return {cgen_state_->ir_builder_.CreatePointerCast(buf1, pi8_type),
342  buf1s,
343  cgen_state_->ir_builder_.CreatePointerCast(buf2, pi32_type),
344  buf2s,
345  cgen_state_->ir_builder_.CreatePointerCast(buf3, pi32_type),
346  buf3s};
347 }
#define CHECK_EQ(x, y)
Definition: Logger.h:205
const SQLTypeInfo getTypeInfo0() const
Definition: Analyzer.h:1551
const std::vector< std::shared_ptr< Analyzer::Expr > > & getArgs0() const
Definition: Analyzer.h:1553
const SQLTypeInfo getTypeInfo0() const
Definition: Analyzer.h:1522
CgenState * cgen_state_
llvm::Value * emitExternalCall(const std::string &fname, llvm::Type *ret_type, const std::vector< llvm::Value * > args, const std::vector< llvm::Attribute::AttrKind > &fnattrs={}, const bool has_struct_return=false)
Definition: CgenState.h:206
llvm::IRBuilder ir_builder_
Definition: CgenState.h:319
llvm::Value * posArg(const Analyzer::Expr *) const
Definition: ColumnIR.cpp:509
const SQLTypeInfo getTypeInfo1() const
Definition: Analyzer.h:1552
llvm::ConstantInt * llBool(const bool v) const
Definition: CgenState.h:310
bool needs_geos_
Definition: CgenState.h:335
static const int32_t ERR_GEOS
Definition: Execute.h:949
HOST DEVICE SQLTypes get_type() const
Definition: sqltypes.h:258
llvm::Type * get_int_type(const int width, llvm::LLVMContext &context)
std::vector< llvm::Value * > codegenGeoBinOper(const Analyzer::GeoBinOper *, const CompilationOptions &)
Definition: GeoIR.cpp:80
llvm::Function * row_func_
Definition: CgenState.h:315
llvm::LLVMContext & context_
Definition: CgenState.h:317
CHECK(cgen_state)
std::vector< llvm::Value * > codegenGeoUOper(const Analyzer::GeoUOper *, const CompilationOptions &)
Definition: GeoIR.cpp:21
const std::vector< std::shared_ptr< Analyzer::Expr > > & getArgs0() const
Definition: Analyzer.h:1523
std::vector< llvm::Value * > codegenGeosConstructorCall(const std::string &, std::vector< llvm::Value * >, const CompilationOptions &)
Definition: GeoIR.cpp:257
bool needs_error_check_
Definition: CgenState.h:334
Geo_namespace::GeoBase::GeoOp getOp() const
Definition: Analyzer.h:1550
const SQLTypeInfo & get_type_info() const
Definition: Analyzer.h:79
ExecutorDeviceType device_type
std::vector< llvm::Value * > codegen(const Analyzer::Expr *, const bool fetch_columns, const CompilationOptions &)
Definition: IRCodegen.cpp:26
std::vector< llvm::Value * > codegenGeosPredicateCall(const std::string &, std::vector< llvm::Value * >, const CompilationOptions &)
Definition: GeoIR.cpp:226
llvm::ConstantInt * llInt(const T v) const
Definition: CgenState.h:296
std::vector< llvm::Value * > codegenGeoArgs(const std::vector< std::shared_ptr< Analyzer::Expr >> &, const CompilationOptions &)
Definition: GeoIR.cpp:162
int32_t get_compression_scheme(const SQLTypeInfo &ti)
uint32_t log2_bytes(const uint32_t bytes)
Definition: Execute.h:105
Geo_namespace::GeoBase::GeoOp getOp() const
Definition: Analyzer.h:1521
int get_physical_coord_cols() const
Definition: sqltypes.h:294
const std::vector< std::shared_ptr< Analyzer::Expr > > & getArgs1() const
Definition: Analyzer.h:1554
HOST DEVICE int get_output_srid() const
Definition: sqltypes.h:264
Executor * executor() const