OmniSciDB  dfae7c3b14
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  for (size_t i = 0; i < array_expr->getElementCount(); i++) {
101  const auto arg = array_expr->getElement(i);
102  const auto arg_lvs = codegen(arg, true, co);
103  if (arg_lvs.size() == 1) {
104  argument_list.push_back(arg_lvs.front());
105  } else {
106  throw std::runtime_error(
107  "Unexpected argument count during array[] code generation.");
108  }
109  }
110 
111  auto array_element_size_bytes =
112  return_type.get_elem_type().get_array_context_logical_size();
113  auto* array_index_type =
114  get_int_type(array_element_size_bytes * 8, cgen_state_->context_);
115  auto* array_type = get_int_array_type(
116  array_element_size_bytes * 8, array_expr->getElementCount(), cgen_state_->context_);
117 
118  if (array_expr->isNull()) {
119  return {llvm::ConstantPointerNull::get(
120  llvm::PointerType::get(get_int_type(64, cgen_state_->context_), 0)),
121  cgen_state_->llInt(0)};
122  }
123 
124  if (0 == array_expr->getElementCount()) {
125  llvm::Constant* dead_const = cgen_state_->llInt(0xdead);
126  llvm::Value* dead_pointer = llvm::ConstantExpr::getIntToPtr(
127  dead_const, llvm::PointerType::get(get_int_type(64, cgen_state_->context_), 0));
128  return {dead_pointer, cgen_state_->llInt(0)};
129  }
130 
131  llvm::Value* allocated_target_buffer;
132  if (array_expr->isLocalAlloc()) {
133  allocated_target_buffer = ir_builder.CreateAlloca(array_type);
134  } else {
136  throw QueryMustRunOnCpu();
137  }
138 
139  allocated_target_buffer =
140  cgen_state_->emitExternalCall("allocate_varlen_buffer",
141  llvm::Type::getInt8PtrTy(cgen_state_->context_),
142  {cgen_state_->llInt(array_expr->getElementCount()),
143  cgen_state_->llInt(array_element_size_bytes)});
145  "register_buffer_with_executor_rsm",
146  llvm::Type::getVoidTy(cgen_state_->context_),
147  {cgen_state_->llInt(reinterpret_cast<int64_t>(executor())),
148  allocated_target_buffer});
149  }
150  llvm::Value* casted_allocated_target_buffer =
151  ir_builder.CreatePointerCast(allocated_target_buffer, array_type->getPointerTo());
152 
153  for (size_t i = 0; i < array_expr->getElementCount(); i++) {
154  auto* element = argument_list[i];
155  auto* element_ptr = ir_builder.CreateGEP(
156  array_type,
157  casted_allocated_target_buffer,
158  std::vector<llvm::Value*>{cgen_state_->llInt(0), cgen_state_->llInt(i)});
159 
160  const auto& elem_ti = return_type.get_elem_type();
161  if (elem_ti.is_boolean()) {
162  const auto byte_casted_bit =
163  ir_builder.CreateIntCast(element, array_index_type, true);
164  ir_builder.CreateStore(byte_casted_bit, element_ptr);
165  } else if (elem_ti.is_fp()) {
166  switch (elem_ti.get_size()) {
167  case sizeof(double): {
168  const auto double_element_ptr = ir_builder.CreatePointerCast(
169  element_ptr, llvm::Type::getDoublePtrTy(cgen_state_->context_));
170  ir_builder.CreateStore(element, double_element_ptr);
171  break;
172  }
173  case sizeof(float): {
174  const auto float_element_ptr = ir_builder.CreatePointerCast(
175  element_ptr, llvm::Type::getFloatPtrTy(cgen_state_->context_));
176  ir_builder.CreateStore(element, float_element_ptr);
177  break;
178  }
179  default:
180  UNREACHABLE();
181  }
182  } else if (elem_ti.is_integer() || elem_ti.is_decimal() || elem_ti.is_date() ||
183  elem_ti.is_timestamp() || elem_ti.is_time() || elem_ti.is_timeinterval() ||
184  elem_ti.is_dict_encoded_string()) {
185  // TODO(adb): this validation and handling should be done elsewhere
186  const auto sign_extended_element = ir_builder.CreateSExt(element, array_index_type);
187  ir_builder.CreateStore(sign_extended_element, element_ptr);
188  } else {
189  throw std::runtime_error("Unsupported type used in ARRAY construction.");
190  }
191  }
192 
193  return {ir_builder.CreateGEP(
194  array_type, casted_allocated_target_buffer, cgen_state_->llInt(0)),
195  cgen_state_->llInt(array_expr->getElementCount())};
196 }
#define CHECK_EQ(x, y)
Definition: Logger.h:205
size_t getElementCount() const
Definition: Analyzer.h:1488
CgenState * cgen_state_
llvm::IRBuilder ir_builder_
Definition: CgenState.h:341
#define UNREACHABLE()
Definition: Logger.h:241
bool isLocalAlloc() const
Definition: Analyzer.h:1489
llvm::Value * codegenArrayAt(const Analyzer::BinOper *, const CompilationOptions &)
Definition: ArrayIR.cpp:26
llvm::Type * get_int_type(const int width, llvm::LLVMContext &context)
const Expr * get_arg() const
Definition: Analyzer.h:851
std::string to_string(char const *&&v)
const Analyzer::Expr * getElement(const size_t i) const
Definition: Analyzer.h:1492
llvm::LLVMContext & context_
Definition: CgenState.h:339
llvm::ConstantInt * inlineIntNull(const SQLTypeInfo &)
Definition: CgenState.cpp:27
std::vector< llvm::Value * > codegenArrayExpr(const Analyzer::ArrayExpr *, const CompilationOptions &)
Definition: ArrayIR.cpp:91
#define AUTOMATIC_IR_METADATA(CGENSTATE)
ExecutorDeviceType device_type
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:222
std::vector< llvm::Value * > codegen(const Analyzer::Expr *, const bool fetch_columns, const CompilationOptions &)
Definition: IRCodegen.cpp:26
const SQLTypeInfo & get_type_info() const
Definition: Analyzer.h:78
llvm::Value * codegenUnnest(const Analyzer::UOper *, const CompilationOptions &)
Definition: ArrayIR.cpp:20
llvm::Value * posArg(const Analyzer::Expr *) const
Definition: ColumnIR.cpp:515
#define CHECK(condition)
Definition: Logger.h:197
uint32_t log2_bytes(const uint32_t bytes)
Definition: Execute.h:139
llvm::ArrayType * get_int_array_type(int const width, int count, llvm::LLVMContext &context)
bool isNull() const
Definition: Analyzer.h:1490
llvm::ConstantInt * llInt(const T v) const
Definition: CgenState.h:312
const Expr * get_right_operand() const
Definition: Analyzer.h:443
llvm::ConstantFP * inlineFpNull(const SQLTypeInfo &)
Definition: CgenState.cpp:65
const Expr * get_left_operand() const
Definition: Analyzer.h:442
const Expr * get_operand() const
Definition: Analyzer.h:371