OmniSciDB  6686921089
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Centroid.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 Centroid : public Codegen {
24  public:
25  Centroid(const Analyzer::GeoOperator* geo_operator,
26  const Catalog_Namespace::Catalog* catalog)
27  : Codegen(geo_operator, catalog) {
28  CHECK_EQ(operator_->size(), size_t(1));
29  const auto& ti = operator_->get_type_info();
30  is_nullable_ = !ti.get_notnull();
31  }
32 
33  size_t size() const final { return 1; }
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  const auto operand = getOperand(0);
43  CHECK(operand);
44  const auto& operand_ti = operand->get_type_info();
45 
46  std::string size_fn_name = "array_size";
47  if (is_nullable_) {
48  size_fn_name += "_nullable";
49  }
50 
51  const uint32_t coords_elem_sz_bytes =
52  operand_ti.get_compression() == kENCODING_GEOINT ? 1 : 8;
53  auto& builder = cgen_state->ir_builder_;
54 
55  std::vector<llvm::Value*> operand_lvs;
56  // iterate over column inputs
57  if (dynamic_cast<const Analyzer::ColumnVar*>(operand)) {
58  for (size_t i = 0; i < arg_lvs.size(); i++) {
59  auto lv = arg_lvs[i];
60  auto array_buff_lv =
61  cgen_state->emitExternalCall("array_buff",
62  llvm::Type::getInt8PtrTy(cgen_state->context_),
63  {lv, pos_lvs.front()});
64  if (i > 0) {
65  array_buff_lv = builder.CreateBitCast(
66  array_buff_lv, llvm::Type::getInt32PtrTy(cgen_state->context_));
67  }
68  operand_lvs.push_back(array_buff_lv);
69  const auto ptr_type = llvm::dyn_cast_or_null<llvm::PointerType>(lv->getType());
70  CHECK(ptr_type);
71  const auto elem_type = ptr_type->getElementType();
72  CHECK(elem_type);
73  std::vector<llvm::Value*> array_sz_args{
74  lv,
75  pos_lvs.front(),
76  cgen_state->llInt(log2_bytes(i == 0 ? coords_elem_sz_bytes : 4))};
77  if (is_nullable_) { // TODO: should we do this for all arguments, or just points?
78  array_sz_args.push_back(
79  cgen_state->llInt(static_cast<int32_t>(inline_int_null_value<int32_t>())));
80  }
81  operand_lvs.push_back(builder.CreateSExt(
82  cgen_state->emitExternalCall(
83  size_fn_name, get_int_type(32, cgen_state->context_), array_sz_args),
84  llvm::Type::getInt64Ty(cgen_state->context_)));
85  }
86  } else {
87  for (size_t i = 0; i < arg_lvs.size(); i++) {
88  auto arg_lv = arg_lvs[i];
89  if (i > 0 && arg_lv->getType()->isPointerTy()) {
90  arg_lv = builder.CreateBitCast(arg_lv,
91  llvm::Type::getInt32PtrTy(cgen_state->context_));
92  }
93  operand_lvs.push_back(arg_lv);
94  }
95  }
96  CHECK_EQ(operand_lvs.size(),
97  size_t(2 * operand_ti.get_physical_coord_cols())); // array ptr and size
98 
99  // note that this block is the only one that differs from Area/Perimeter
100  // use the points array size argument for nullability
101  llvm::Value* null_check_operand_lv{nullptr};
102  if (is_nullable_) {
103  null_check_operand_lv = operand_lvs[1];
104  if (null_check_operand_lv->getType() !=
105  llvm::Type::getInt32Ty(cgen_state->context_)) {
106  CHECK(null_check_operand_lv->getType() ==
107  llvm::Type::getInt64Ty(cgen_state->context_));
108  // Geos functions come out 64-bit, cast down to 32 for now
109 
110  null_check_operand_lv = builder.CreateTrunc(
111  null_check_operand_lv, llvm::Type::getInt32Ty(cgen_state->context_));
112  }
113  }
114 
115  return std::make_tuple(operand_lvs, null_check_operand_lv);
116  }
117 
118  std::vector<llvm::Value*> codegen(const std::vector<llvm::Value*>& args,
119  CodeGenerator::NullCheckCodegen* nullcheck_codegen,
120  CgenState* cgen_state,
121  const CompilationOptions& co) final {
122  std::string func_name = "ST_Centroid";
123  const auto& ret_ti = operator_->get_type_info();
124  CHECK(ret_ti.is_geometry() && ret_ti.get_type() == kPOINT);
125  const auto& operand_ti = getOperand(0)->get_type_info();
126 
127  auto& builder = cgen_state->ir_builder_;
128 
129  // Allocate local storage for centroid point
130  auto elem_ty = llvm::Type::getDoubleTy(cgen_state->context_);
131  llvm::ArrayType* arr_type = llvm::ArrayType::get(elem_ty, 2);
132  auto pt_local_storage_lv =
133  builder.CreateAlloca(arr_type, nullptr, func_name + "_Local_Storage");
134 
135  llvm::Value* pt_compressed_local_storage_lv{NULL};
136  // Allocate local storage for compressed centroid point
137  if (ret_ti.get_compression() == kENCODING_GEOINT) {
138  auto elem_ty = llvm::Type::getInt32Ty(cgen_state->context_);
139  llvm::ArrayType* arr_type = llvm::ArrayType::get(elem_ty, 2);
140  pt_compressed_local_storage_lv = builder.CreateAlloca(
141  arr_type, nullptr, func_name + "_Compressed_Local_Storage");
142  }
143 
144  func_name += spatial_type::suffix(operand_ti.get_type());
145 
146  auto operand_lvs = args;
147 
148  // push back ic, isr, osr for now
149  operand_lvs.push_back(
150  cgen_state->llInt(Geospatial::get_compression_scheme(operand_ti))); // ic
151  operand_lvs.push_back(cgen_state->llInt(operand_ti.get_input_srid())); // in srid
152  operand_lvs.push_back(cgen_state->llInt(operand_ti.get_output_srid())); // out srid
153 
154  auto idx_lv = cgen_state->llInt(0);
155  auto pt_local_storage_gep = llvm::GetElementPtrInst::CreateInBounds(
156  pt_local_storage_lv, {idx_lv, idx_lv}, "", builder.GetInsertBlock());
157  // Pass local storage to centroid function
158  operand_lvs.push_back(pt_local_storage_gep);
159  CHECK(ret_ti.get_type() == kPOINT);
160  cgen_state->emitExternalCall(
161  func_name, llvm::Type::getVoidTy(cgen_state->context_), operand_lvs);
162 
163  llvm::Value* ret_coords = pt_local_storage_lv;
164  if (ret_ti.get_compression() == kENCODING_GEOINT) {
165  // Compress centroid point if requested
166  // Take values out of local storage, compress, store in compressed local storage
167 
168  auto x_ptr = builder.CreateGEP(
169  pt_local_storage_lv, {cgen_state->llInt(0), cgen_state->llInt(0)}, "x_ptr");
170  auto x_lv = builder.CreateLoad(x_ptr);
171  auto compressed_x_lv =
172  cgen_state->emitExternalCall("compress_x_coord_geoint",
173  llvm::Type::getInt32Ty(cgen_state->context_),
174  {x_lv});
175  auto compressed_x_ptr =
176  builder.CreateGEP(pt_compressed_local_storage_lv,
177  {cgen_state->llInt(0), cgen_state->llInt(0)},
178  "compressed_x_ptr");
179  builder.CreateStore(compressed_x_lv, compressed_x_ptr);
180 
181  auto y_ptr = builder.CreateGEP(
182  pt_local_storage_lv, {cgen_state->llInt(0), cgen_state->llInt(1)}, "y_ptr");
183  auto y_lv = builder.CreateLoad(y_ptr);
184  auto compressed_y_lv =
185  cgen_state->emitExternalCall("compress_y_coord_geoint",
186  llvm::Type::getInt32Ty(cgen_state->context_),
187  {y_lv});
188  auto compressed_y_ptr =
189  builder.CreateGEP(pt_compressed_local_storage_lv,
190  {cgen_state->llInt(0), cgen_state->llInt(1)},
191  "compressed_y_ptr");
192  builder.CreateStore(compressed_y_lv, compressed_y_ptr);
193 
194  ret_coords = pt_compressed_local_storage_lv;
195  } else {
196  CHECK(ret_ti.get_compression() == kENCODING_NONE);
197  }
198 
199  auto ret_ty = ret_ti.get_compression() == kENCODING_GEOINT
200  ? llvm::Type::getInt32PtrTy(cgen_state->context_)
201  : llvm::Type::getDoublePtrTy(cgen_state->context_);
202  ret_coords = builder.CreateBitCast(ret_coords, ret_ty);
203 
204  if (is_nullable_) {
205  CHECK(nullcheck_codegen);
206  ret_coords = nullcheck_codegen->finalize(
207  llvm::ConstantPointerNull::get(
208  ret_ti.get_compression() == kENCODING_GEOINT
209  ? llvm::PointerType::get(llvm::Type::getInt32Ty(cgen_state->context_),
210  0)
211  : llvm::PointerType::get(llvm::Type::getDoubleTy(cgen_state->context_),
212  0)),
213  ret_coords);
214  }
215 
216  return {ret_coords,
217  cgen_state->llInt(ret_ti.get_compression() == kENCODING_GEOINT ? 8 : 16)};
218  }
219 };
220 
221 } // 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::vector< llvm::Value * > codegen(const std::vector< llvm::Value * > &args, CodeGenerator::NullCheckCodegen *nullcheck_codegen, CgenState *cgen_state, const CompilationOptions &co) final
Definition: Centroid.h:118
std::string suffix(SQLTypes type)
Definition: Codegen.cpp:68
const SQLTypeInfo & get_type_info() const
Definition: Analyzer.h:77
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: Centroid.h:37
const Analyzer::GeoOperator * operator_
Definition: Codegen.h:70
size_t size() const
Definition: Analyzer.cpp:3640
size_t size() const final
Definition: Centroid.h:33
#define CHECK(condition)
Definition: Logger.h:209
Centroid(const Analyzer::GeoOperator *geo_operator, const Catalog_Namespace::Catalog *catalog)
Definition: Centroid.h:25
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
Definition: sqltypes.h:45
SQLTypeInfo getNullType() const final
Definition: Centroid.h:35