OmniSciDB  72c90bc290
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ArrayIR.cpp
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 #include "CodeGenerator.h"
18 #include "Execute.h"
19 
21  const CompilationOptions& co) {
23  return codegen(uoper->get_operand(), true, co).front();
24 }
25 
26 llvm::Value* CodeGenerator::codegenArrayAt(const Analyzer::BinOper* array_at,
27  const CompilationOptions& co) {
29  const auto arr_expr = array_at->get_left_operand();
30  const auto idx_expr = array_at->get_right_operand();
31  const auto& idx_ti = idx_expr->get_type_info();
32  CHECK(idx_ti.is_integer());
33  auto idx_lvs = codegen(idx_expr, true, co);
34  CHECK_EQ(size_t(1), idx_lvs.size());
35  auto idx_lv = idx_lvs.front();
36  if (idx_ti.get_logical_size() < 8) {
37  idx_lv = cgen_state_->ir_builder_.CreateCast(llvm::Instruction::CastOps::SExt,
38  idx_lv,
40  }
41  const auto& array_ti = arr_expr->get_type_info();
42  CHECK(array_ti.is_array());
43  const auto& elem_ti = array_ti.get_elem_type();
44  const std::string array_at_fname{
45  elem_ti.is_fp()
46  ? "array_at_" + std::string(elem_ti.get_type() == kDOUBLE ? "double_checked"
47  : "float_checked")
48  : "array_at_int" + std::to_string(elem_ti.get_logical_size() * 8) +
49  "_t_checked"};
50  const auto ret_ty =
51  elem_ti.is_fp()
52  ? (elem_ti.get_type() == kDOUBLE
53  ? llvm::Type::getDoubleTy(cgen_state_->context_)
54  : llvm::Type::getFloatTy(cgen_state_->context_))
55  : get_int_type(elem_ti.get_logical_size() * 8, cgen_state_->context_);
56  const auto arr_lvs = codegen(arr_expr, true, co);
57  CHECK_EQ(size_t(1), arr_lvs.size());
59  array_at_fname,
60  ret_ty,
61  {arr_lvs.front(),
62  posArg(arr_expr),
63  idx_lv,
64  elem_ti.is_fp() ? static_cast<llvm::Value*>(cgen_state_->inlineFpNull(elem_ti))
65  : static_cast<llvm::Value*>(cgen_state_->inlineIntNull(elem_ti))});
66 }
67 
69  const CompilationOptions& co) {
71  const auto arr_expr = expr->get_arg();
72  const auto& array_ti = arr_expr->get_type_info();
73  CHECK(array_ti.is_array());
74  const auto& elem_ti = array_ti.get_elem_type();
75  auto arr_lv = codegen(arr_expr, true, co);
76  std::string fn_name("array_size");
77 
78  if (auto alloca = llvm::dyn_cast<llvm::AllocaInst>(arr_lv.front())) {
79  if (alloca->getAllocatedType()->isStructTy()) {
80  throw std::runtime_error("Unsupported type used in 'cardinality'");
81  }
82  }
83 
84  std::vector<llvm::Value*> array_size_args{
85  arr_lv.front(),
86  posArg(arr_expr),
87  cgen_state_->llInt(log2_bytes(elem_ti.get_logical_size()))};
88  const bool is_nullable{!arr_expr->get_type_info().get_notnull()};
89  if (is_nullable) {
90  fn_name += "_nullable";
91  array_size_args.push_back(cgen_state_->inlineIntNull(expr->get_type_info()));
92  }
94  fn_name, get_int_type(32, cgen_state_->context_), array_size_args);
95 }
96 
97 std::vector<llvm::Value*> CodeGenerator::codegenArrayExpr(
98  Analyzer::ArrayExpr const* array_expr,
99  CompilationOptions const& co) {
101  using ValueVector = std::vector<llvm::Value*>;
102  ValueVector argument_list;
103  auto& ir_builder(cgen_state_->ir_builder_);
104 
105  const auto& return_type = array_expr->get_type_info();
106  auto coord_compression = (return_type.get_compression() == kENCODING_GEOINT);
107  if (coord_compression) {
108  CHECK(array_expr->isLocalAlloc() && array_expr->getElementCount() == 2);
109  }
110  for (size_t i = 0; i < array_expr->getElementCount(); i++) {
111  const auto arg = array_expr->getElement(i);
112  const auto arg_lvs = codegen(arg, true, co);
113  if (arg_lvs.size() == 1) {
114  if (coord_compression) {
115  // Compress double coords on the fly
116  auto mult = cgen_state_->llFp(2147483647.0 / (i == 0 ? 180.0 : 90.0));
117  auto c = ir_builder.CreateCast(llvm::Instruction::CastOps::FPToSI,
118  ir_builder.CreateFMul(arg_lvs.front(), mult),
120  argument_list.push_back(c);
121  } else {
122  argument_list.push_back(arg_lvs.front());
123  }
124  } else {
125  throw std::runtime_error(
126  "Unexpected argument count during array[] code generation.");
127  }
128  }
129 
130  auto array_element_size_bytes =
131  return_type.get_elem_type().get_array_context_logical_size();
132  auto* array_index_type =
133  get_int_type(array_element_size_bytes * 8, cgen_state_->context_);
134  auto* array_type = get_int_array_type(
135  array_element_size_bytes * 8, array_expr->getElementCount(), cgen_state_->context_);
136 
137  if (array_expr->isNull()) {
138  return {llvm::ConstantPointerNull::get(
139  llvm::PointerType::get(get_int_type(64, cgen_state_->context_), 0)),
140  cgen_state_->llInt(0)};
141  }
142 
143  if (0 == array_expr->getElementCount()) {
144  llvm::Constant* dead_const = cgen_state_->llInt(0xdead);
145  llvm::Value* dead_pointer = llvm::ConstantExpr::getIntToPtr(
146  dead_const, llvm::PointerType::get(get_int_type(64, cgen_state_->context_), 0));
147  return {dead_pointer, cgen_state_->llInt(0)};
148  }
149 
150  llvm::Value* allocated_target_buffer;
151  if (array_expr->isLocalAlloc()) {
152  allocated_target_buffer = ir_builder.CreateAlloca(array_type);
153  } else {
155  throw QueryMustRunOnCpu();
156  }
157 
158  allocated_target_buffer =
159  cgen_state_->emitExternalCall("allocate_varlen_buffer",
160  llvm::Type::getInt8PtrTy(cgen_state_->context_),
161  {cgen_state_->llInt(array_expr->getElementCount()),
162  cgen_state_->llInt(array_element_size_bytes)});
164  "register_buffer_with_executor_rsm",
165  llvm::Type::getVoidTy(cgen_state_->context_),
166  {cgen_state_->llInt(reinterpret_cast<int64_t>(executor())),
167  allocated_target_buffer});
168  }
169  llvm::Value* casted_allocated_target_buffer =
170  ir_builder.CreatePointerCast(allocated_target_buffer, array_type->getPointerTo());
171 
172  for (size_t i = 0; i < array_expr->getElementCount(); i++) {
173  auto* element = argument_list[i];
174  auto* element_ptr = ir_builder.CreateGEP(
175  array_type,
176  casted_allocated_target_buffer,
177  std::vector<llvm::Value*>{cgen_state_->llInt(0), cgen_state_->llInt(i)});
178 
179  const auto& elem_ti = return_type.get_elem_type();
180  if (elem_ti.is_boolean()) {
181  const auto byte_casted_bit =
182  ir_builder.CreateIntCast(element, array_index_type, true);
183  ir_builder.CreateStore(byte_casted_bit, element_ptr);
184  } else if (elem_ti.is_fp()) {
185  switch (elem_ti.get_size()) {
186  case sizeof(double): {
187  const auto double_element_ptr = ir_builder.CreatePointerCast(
188  element_ptr, llvm::Type::getDoublePtrTy(cgen_state_->context_));
189  ir_builder.CreateStore(element, double_element_ptr);
190  break;
191  }
192  case sizeof(float): {
193  const auto float_element_ptr = ir_builder.CreatePointerCast(
194  element_ptr, llvm::Type::getFloatPtrTy(cgen_state_->context_));
195  ir_builder.CreateStore(element, float_element_ptr);
196  break;
197  }
198  default:
199  UNREACHABLE();
200  }
201  } else if (elem_ti.is_integer() || elem_ti.is_decimal() || elem_ti.is_date() ||
202  elem_ti.is_timestamp() || elem_ti.is_time() || elem_ti.is_timeinterval() ||
203  elem_ti.is_dict_encoded_string()) {
204  // TODO(adb): this validation and handling should be done elsewhere
205  const auto sign_extended_element = ir_builder.CreateSExt(element, array_index_type);
206  ir_builder.CreateStore(sign_extended_element, element_ptr);
207  } else {
208  throw std::runtime_error("Unsupported type used in ARRAY construction.");
209  }
210  }
211 
212  return {ir_builder.CreateGEP(
213  array_type, casted_allocated_target_buffer, cgen_state_->llInt(0)),
214  cgen_state_->llInt(array_expr->getElementCount())};
215 }
#define CHECK_EQ(x, y)
Definition: Logger.h:301
CgenState * cgen_state_
const Expr * get_right_operand() const
Definition: Analyzer.h:456
llvm::IRBuilder ir_builder_
Definition: CgenState.h:384
llvm::Value * posArg(const Analyzer::Expr *) const
Definition: ColumnIR.cpp:590
#define UNREACHABLE()
Definition: Logger.h:338
llvm::Value * codegenArrayAt(const Analyzer::BinOper *, const CompilationOptions &)
Definition: ArrayIR.cpp:26
bool isNull() const
Definition: Analyzer.h:2894
llvm::Type * get_int_type(const int width, llvm::LLVMContext &context)
std::string to_string(char const *&&v)
llvm::LLVMContext & context_
Definition: CgenState.h:382
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.cpp:395
llvm::ConstantInt * inlineIntNull(const SQLTypeInfo &)
Definition: CgenState.cpp:65
llvm::ConstantFP * llFp(const float v) const
Definition: CgenState.h:253
std::vector< llvm::Value * > codegenArrayExpr(const Analyzer::ArrayExpr *, const CompilationOptions &)
Definition: ArrayIR.cpp:97
#define AUTOMATIC_IR_METADATA(CGENSTATE)
const SQLTypeInfo & get_type_info() const
Definition: Analyzer.h:79
size_t getElementCount() const
Definition: Analyzer.h:2892
ExecutorDeviceType device_type
std::vector< llvm::Value * > codegen(const Analyzer::Expr *, const bool fetch_columns, const CompilationOptions &)
Definition: IRCodegen.cpp:30
bool isLocalAlloc() const
Definition: Analyzer.h:2893
const Expr * get_operand() const
Definition: Analyzer.h:384
llvm::ConstantInt * llInt(const T v) const
Definition: CgenState.h:249
llvm::Value * codegenUnnest(const Analyzer::UOper *, const CompilationOptions &)
Definition: ArrayIR.cpp:20
#define CHECK(condition)
Definition: Logger.h:291
const Expr * get_left_operand() const
Definition: Analyzer.h:455
uint32_t log2_bytes(const uint32_t bytes)
Definition: Execute.h:198
llvm::ArrayType * get_int_array_type(int const width, int count, llvm::LLVMContext &context)
const Expr * get_arg() const
Definition: Analyzer.h:1007
const Analyzer::Expr * getElement(const size_t i) const
Definition: Analyzer.h:2896
llvm::ConstantFP * inlineFpNull(const SQLTypeInfo &)
Definition: CgenState.cpp:104
Executor * executor() const