OmniSciDB  6686921089
 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 2017 MapD Technologies, 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  std::vector<llvm::Value*> array_size_args{
79  arr_lv.front(),
80  posArg(arr_expr),
81  cgen_state_->llInt(log2_bytes(elem_ti.get_logical_size()))};
82  const bool is_nullable{!arr_expr->get_type_info().get_notnull()};
83  if (is_nullable) {
84  fn_name += "_nullable";
85  array_size_args.push_back(cgen_state_->inlineIntNull(expr->get_type_info()));
86  }
88  fn_name, get_int_type(32, cgen_state_->context_), array_size_args);
89 }
90 
91 std::vector<llvm::Value*> CodeGenerator::codegenArrayExpr(
92  Analyzer::ArrayExpr const* array_expr,
93  CompilationOptions const& co) {
95  using ValueVector = std::vector<llvm::Value*>;
96  ValueVector argument_list;
97  auto& ir_builder(cgen_state_->ir_builder_);
98 
99  const auto& return_type = array_expr->get_type_info();
100  auto coord_compression = (return_type.get_compression() == kENCODING_GEOINT);
101  if (coord_compression) {
102  CHECK(array_expr->isLocalAlloc() && array_expr->getElementCount() == 2);
103  }
104  for (size_t i = 0; i < array_expr->getElementCount(); i++) {
105  const auto arg = array_expr->getElement(i);
106  const auto arg_lvs = codegen(arg, true, co);
107  if (arg_lvs.size() == 1) {
108  if (coord_compression) {
109  // Compress double coords on the fly
110  auto mult = cgen_state_->llFp(2147483647.0 / (i == 0 ? 180.0 : 90.0));
111  auto c = ir_builder.CreateCast(llvm::Instruction::CastOps::FPToSI,
112  ir_builder.CreateFMul(arg_lvs.front(), mult),
114  argument_list.push_back(c);
115  } else {
116  argument_list.push_back(arg_lvs.front());
117  }
118  } else {
119  throw std::runtime_error(
120  "Unexpected argument count during array[] code generation.");
121  }
122  }
123 
124  auto array_element_size_bytes =
125  return_type.get_elem_type().get_array_context_logical_size();
126  auto* array_index_type =
127  get_int_type(array_element_size_bytes * 8, cgen_state_->context_);
128  auto* array_type = get_int_array_type(
129  array_element_size_bytes * 8, array_expr->getElementCount(), cgen_state_->context_);
130 
131  if (array_expr->isNull()) {
132  return {llvm::ConstantPointerNull::get(
133  llvm::PointerType::get(get_int_type(64, cgen_state_->context_), 0)),
134  cgen_state_->llInt(0)};
135  }
136 
137  if (0 == array_expr->getElementCount()) {
138  llvm::Constant* dead_const = cgen_state_->llInt(0xdead);
139  llvm::Value* dead_pointer = llvm::ConstantExpr::getIntToPtr(
140  dead_const, llvm::PointerType::get(get_int_type(64, cgen_state_->context_), 0));
141  return {dead_pointer, cgen_state_->llInt(0)};
142  }
143 
144  llvm::Value* allocated_target_buffer;
145  if (array_expr->isLocalAlloc()) {
146  allocated_target_buffer = ir_builder.CreateAlloca(array_type);
147  } else {
149  throw QueryMustRunOnCpu();
150  }
151 
152  allocated_target_buffer =
153  cgen_state_->emitExternalCall("allocate_varlen_buffer",
154  llvm::Type::getInt8PtrTy(cgen_state_->context_),
155  {cgen_state_->llInt(array_expr->getElementCount()),
156  cgen_state_->llInt(array_element_size_bytes)});
158  "register_buffer_with_executor_rsm",
159  llvm::Type::getVoidTy(cgen_state_->context_),
160  {cgen_state_->llInt(reinterpret_cast<int64_t>(executor())),
161  allocated_target_buffer});
162  }
163  llvm::Value* casted_allocated_target_buffer =
164  ir_builder.CreatePointerCast(allocated_target_buffer, array_type->getPointerTo());
165 
166  for (size_t i = 0; i < array_expr->getElementCount(); i++) {
167  auto* element = argument_list[i];
168  auto* element_ptr = ir_builder.CreateGEP(
169  array_type,
170  casted_allocated_target_buffer,
171  std::vector<llvm::Value*>{cgen_state_->llInt(0), cgen_state_->llInt(i)});
172 
173  const auto& elem_ti = return_type.get_elem_type();
174  if (elem_ti.is_boolean()) {
175  const auto byte_casted_bit =
176  ir_builder.CreateIntCast(element, array_index_type, true);
177  ir_builder.CreateStore(byte_casted_bit, element_ptr);
178  } else if (elem_ti.is_fp()) {
179  switch (elem_ti.get_size()) {
180  case sizeof(double): {
181  const auto double_element_ptr = ir_builder.CreatePointerCast(
182  element_ptr, llvm::Type::getDoublePtrTy(cgen_state_->context_));
183  ir_builder.CreateStore(element, double_element_ptr);
184  break;
185  }
186  case sizeof(float): {
187  const auto float_element_ptr = ir_builder.CreatePointerCast(
188  element_ptr, llvm::Type::getFloatPtrTy(cgen_state_->context_));
189  ir_builder.CreateStore(element, float_element_ptr);
190  break;
191  }
192  default:
193  UNREACHABLE();
194  }
195  } else if (elem_ti.is_integer() || elem_ti.is_decimal() || elem_ti.is_date() ||
196  elem_ti.is_timestamp() || elem_ti.is_time() || elem_ti.is_timeinterval() ||
197  elem_ti.is_dict_encoded_string()) {
198  // TODO(adb): this validation and handling should be done elsewhere
199  const auto sign_extended_element = ir_builder.CreateSExt(element, array_index_type);
200  ir_builder.CreateStore(sign_extended_element, element_ptr);
201  } else {
202  throw std::runtime_error("Unsupported type used in ARRAY construction.");
203  }
204  }
205 
206  return {ir_builder.CreateGEP(
207  array_type, casted_allocated_target_buffer, cgen_state_->llInt(0)),
208  cgen_state_->llInt(array_expr->getElementCount())};
209 }
#define CHECK_EQ(x, y)
Definition: Logger.h:217
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:228
const Expr * get_right_operand() const
Definition: Analyzer.h:442
llvm::IRBuilder ir_builder_
Definition: CgenState.h:340
llvm::Value * posArg(const Analyzer::Expr *) const
Definition: ColumnIR.cpp:512
#define UNREACHABLE()
Definition: Logger.h:253
llvm::Value * codegenArrayAt(const Analyzer::BinOper *, const CompilationOptions &)
Definition: ArrayIR.cpp:26
bool isNull() const
Definition: Analyzer.h:1650
llvm::Type * get_int_type(const int width, llvm::LLVMContext &context)
std::string to_string(char const *&&v)
llvm::LLVMContext & context_
Definition: CgenState.h:338
llvm::ConstantInt * inlineIntNull(const SQLTypeInfo &)
Definition: CgenState.cpp:29
llvm::ConstantFP * llFp(const float v) const
Definition: CgenState.h:311
std::vector< llvm::Value * > codegenArrayExpr(const Analyzer::ArrayExpr *, const CompilationOptions &)
Definition: ArrayIR.cpp:91
#define AUTOMATIC_IR_METADATA(CGENSTATE)
const SQLTypeInfo & get_type_info() const
Definition: Analyzer.h:77
size_t getElementCount() const
Definition: Analyzer.h:1648
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:1649
const Expr * get_operand() const
Definition: Analyzer.h:370
llvm::ConstantInt * llInt(const T v) const
Definition: CgenState.h:307
llvm::Value * codegenUnnest(const Analyzer::UOper *, const CompilationOptions &)
Definition: ArrayIR.cpp:20
#define CHECK(condition)
Definition: Logger.h:209
const Expr * get_left_operand() const
Definition: Analyzer.h:441
uint32_t log2_bytes(const uint32_t bytes)
Definition: Execute.h:174
llvm::ArrayType * get_int_array_type(int const width, int count, llvm::LLVMContext &context)
const Expr * get_arg() const
Definition: Analyzer.h:897
const Analyzer::Expr * getElement(const size_t i) const
Definition: Analyzer.h:1652
llvm::ConstantFP * inlineFpNull(const SQLTypeInfo &)
Definition: CgenState.cpp:67
Executor * executor() const