OmniSciDB  a5dc49c757
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PointConstructor.h
Go to the documentation of this file.
1 /*
2  * Copyright 2022 HEAVY.AI, 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 #include "Shared/SqlTypesLayout.h"
22 
23 namespace spatial_type {
24 
25 // ST_Point
26 class PointConstructor : public Codegen {
27  public:
28  PointConstructor(const Analyzer::GeoOperator* geo_operator) : Codegen(geo_operator) {
29  CHECK_EQ(operator_->size(), size_t(2));
30  const auto& ti = geo_operator->get_type_info();
31  if (ti.get_notnull()) {
32  is_nullable_ = false;
33  } else {
34  is_nullable_ = true;
35  }
36  }
37 
38  std::unique_ptr<CodeGenerator::NullCheckCodegen> getNullCheckCodegen(
39  llvm::Value* null_lv,
40  CgenState* cgen_state,
41  Executor* executor) final {
42  if (isNullable()) {
43  // do the standard nullcheck codegen, but modify the null basic block to emplace the
44  // null sentinel into the array
45  auto nullcheck_codegen = std::make_unique<CodeGenerator::NullCheckCodegen>(
46  cgen_state, executor, null_lv, getNullType(), getName() + "_nullcheck");
47 
48  auto& builder = cgen_state->ir_builder_;
50 
51  auto prev_insert_block = builder.GetInsertBlock();
52  auto crt_insert_block = nullcheck_codegen->null_check->cond_true_;
53  CHECK(crt_insert_block);
54  auto& instruction_list = crt_insert_block->getInstList();
55  CHECK_EQ(instruction_list.size(), size_t(1));
56  builder.SetInsertPoint(crt_insert_block, instruction_list.begin());
57 
58  auto x_coord_ptr = builder.CreateGEP(
59  pt_local_storage_lv_->getType()->getScalarType()->getPointerElementType(),
61  {cgen_state->llInt(0), cgen_state->llInt(0)},
62  "x_coord_ptr");
63  const auto& geo_ti = operator_->get_type_info();
64  if (geo_ti.get_compression() == kENCODING_GEOINT) {
65  // TODO: probably wrong
66  builder.CreateStore(cgen_state->llInt(inline_int_null_val(SQLTypeInfo(kINT))),
67  x_coord_ptr);
68  } else {
69  builder.CreateStore(cgen_state->llFp(static_cast<double>(NULL_ARRAY_DOUBLE)),
70  x_coord_ptr);
71  }
72  builder.SetInsertPoint(prev_insert_block);
73 
74  return nullcheck_codegen;
75  } else {
76  return nullptr;
77  }
78  }
79 
80  size_t size() const final { return 2; }
81 
82  SQLTypeInfo getNullType() const final { return SQLTypeInfo(kBOOLEAN); }
83 
84  // returns arguments lvs and null lv
85  std::tuple<std::vector<llvm::Value*>, llvm::Value*> codegenLoads(
86  const std::vector<llvm::Value*>& arg_lvs,
87  const std::vector<llvm::Value*>& pos_lvs,
88  CgenState* cgen_state) final {
89  CHECK_EQ(pos_lvs.size(),
90  size()); // note both pos arguments should be the same, as both inputs are
91  // expected to be from the same table, though this is moot in this
92  // function as position argumnts are not used here
93  CHECK_EQ(arg_lvs.size(), size_t(2));
94 
95  // TODO(adb): centralize nullcheck logic for all sqltypes
96  llvm::Value* const x_is_null = codegenOperandIsNull(0u, arg_lvs[0], cgen_state);
97  llvm::Value* const y_is_null = codegenOperandIsNull(1u, arg_lvs[1], cgen_state);
98  llvm::Value* const is_null =
99  x_is_null && y_is_null ? cgen_state->ir_builder_.CreateOr(x_is_null, y_is_null)
100  : std::max(x_is_null, y_is_null);
101 
102  if (is_nullable_ && !is_null) {
103  // if the inputs are not null, set the output to be not null
104  // TODO: we should do this in the translator and just confirm it here
105  is_nullable_ = false;
106  }
107 
108  // do the alloca before nullcheck codegen, as either way we will return a point array
109  const auto& geo_ti = operator_->get_type_info();
110  CHECK(geo_ti.get_type() == kPOINT);
111 
112  llvm::ArrayType* arr_type{nullptr};
113  if (geo_ti.get_compression() == kENCODING_GEOINT) {
114  auto elem_ty = llvm::Type::getInt32Ty(cgen_state->context_);
115  arr_type = llvm::ArrayType::get(elem_ty, 2);
116  } else {
117  CHECK(geo_ti.get_compression() == kENCODING_NONE);
118  auto elem_ty = llvm::Type::getDoubleTy(cgen_state->context_);
119  arr_type = llvm::ArrayType::get(elem_ty, 2);
120  }
121  pt_local_storage_lv_ = cgen_state->ir_builder_.CreateAlloca(
122  arr_type, nullptr, operator_->getName() + "_Local_Storage");
123 
124  return std::make_tuple(arg_lvs, is_null);
125  }
126 
127  std::vector<llvm::Value*> codegen(const std::vector<llvm::Value*>& args,
128  CodeGenerator::NullCheckCodegen* nullcheck_codegen,
129  CgenState* cgen_state,
130  const CompilationOptions& co) final {
131  CHECK_EQ(args.size(), size_t(2));
132 
133  const auto& geo_ti = operator_->get_type_info();
134  CHECK(geo_ti.get_type() == kPOINT);
135 
136  auto& builder = cgen_state->ir_builder_;
138 
139  const bool is_compressed = geo_ti.get_compression() == kENCODING_GEOINT;
140 
141  // store x coord
142  auto x_coord_ptr = builder.CreateGEP(
143  pt_local_storage_lv_->getType()->getScalarType()->getPointerElementType(),
145  {cgen_state->llInt(0), cgen_state->llInt(0)},
146  "x_coord_ptr");
147  if (is_compressed) {
148  auto compressed_lv =
149  cgen_state->emitExternalCall("compress_x_coord_geoint",
150  llvm::Type::getInt32Ty(cgen_state->context_),
151  {args.front()});
152  builder.CreateStore(compressed_lv, x_coord_ptr);
153  } else {
154  builder.CreateStore(args.front(), x_coord_ptr);
155  }
156 
157  // store y coord
158  auto y_coord_ptr = builder.CreateGEP(
159  pt_local_storage_lv_->getType()->getScalarType()->getPointerElementType(),
161  {cgen_state->llInt(0), cgen_state->llInt(1)},
162  "y_coord_ptr");
163  if (is_compressed) {
164  auto compressed_lv =
165  cgen_state->emitExternalCall("compress_y_coord_geoint",
166  llvm::Type::getInt32Ty(cgen_state->context_),
167  {args.back()});
168  builder.CreateStore(compressed_lv, y_coord_ptr);
169  } else {
170  builder.CreateStore(args.back(), y_coord_ptr);
171  }
172 
173  llvm::Value* ret = pt_local_storage_lv_;
174  if (is_nullable_) {
175  CHECK(nullcheck_codegen);
176  ret = nullcheck_codegen->finalize(ret, ret);
177  }
178  return {builder.CreateBitCast(ret,
179  geo_ti.get_compression() == kENCODING_GEOINT
180  ? llvm::Type::getInt32PtrTy(cgen_state->context_)
181  : llvm::Type::getDoublePtrTy(cgen_state->context_)),
182  cgen_state->llInt(static_cast<int32_t>(
183  geo_ti.get_compression() == kENCODING_GEOINT ? 8 : 16))};
184  }
185 
186  private:
187  llvm::Value* codegenOperandIsNull(size_t idx,
188  llvm::Value* value,
189  CgenState* cgen_state) {
190  auto const& ti = getOperand(idx)->get_type_info();
191  if (ti.get_notnull()) {
192  return nullptr;
193  } else if (ti.is_integer()) {
194  return cgen_state->ir_builder_.CreateICmpEQ(
195  value, cgen_state->llInt(inline_int_null_val(ti)));
196  } else if (ti.is_fp()) {
197  return cgen_state->ir_builder_.CreateFCmpOEQ(
198  value, cgen_state->llFp(inline_fp_null_val(ti)));
199  } else {
200  UNREACHABLE() << "Type is expected to be integer or floating point.";
201  return {};
202  }
203  }
204 
205  llvm::AllocaInst* pt_local_storage_lv_{nullptr};
206 };
207 
208 } // namespace spatial_type
std::vector< llvm::Value * > codegen(const std::vector< llvm::Value * > &args, CodeGenerator::NullCheckCodegen *nullcheck_codegen, CgenState *cgen_state, const CompilationOptions &co) final
#define CHECK_EQ(x, y)
Definition: Logger.h:301
SQLTypeInfo getNullType() const final
llvm::Value * codegenOperandIsNull(size_t idx, llvm::Value *value, CgenState *cgen_state)
llvm::IRBuilder ir_builder_
Definition: CgenState.h:384
#define UNREACHABLE()
Definition: Logger.h:338
double inline_fp_null_val(const SQL_TYPE_INFO &ti)
CONSTEXPR DEVICE bool is_null(const T &value)
const std::string & getName() const
Definition: Analyzer.h:3298
PointConstructor(const Analyzer::GeoOperator *geo_operator)
llvm::ConstantFP * llFp(const float v) const
Definition: CgenState.h:253
auto isNullable() const
Definition: Codegen.h:32
const SQLTypeInfo & get_type_info() const
Definition: Analyzer.h:79
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
llvm::AllocaInst * pt_local_storage_lv_
const Analyzer::GeoOperator * operator_
Definition: Codegen.h:69
size_t size() const
Definition: Analyzer.cpp:4211
#define NULL_ARRAY_DOUBLE
llvm::ConstantInt * llInt(const T v) const
Definition: CgenState.h:249
#define CHECK(condition)
Definition: Logger.h:291
int64_t inline_int_null_val(const SQL_TYPE_INFO &ti)
std::string getName() const
Definition: Codegen.h:36
std::unique_ptr< CodeGenerator::NullCheckCodegen > getNullCheckCodegen(llvm::Value *null_lv, CgenState *cgen_state, Executor *executor) final
Definition: sqltypes.h:72