OmniSciDB  a5dc49c757
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ArithmeticIR.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 
20 #include "Parser/ParserNode.h"
21 
22 // Code generation routines and helpers for basic arithmetic and unary minus.
23 
24 using heavyai::ErrorCode;
25 
26 namespace {
27 
29  const SQLTypeInfo& ti2) {
30  if (ti2.is_timeinterval()) {
31  return numeric_type_name(ti2);
32  }
33  return numeric_type_name(ti1);
34 }
35 
36 } // namespace
37 
38 llvm::Value* CodeGenerator::codegenArith(const Analyzer::BinOper* bin_oper,
39  const CompilationOptions& co) {
41  const auto optype = bin_oper->get_optype();
42  CHECK(IS_ARITHMETIC(optype));
43  const auto lhs = bin_oper->get_left_operand();
44  const auto rhs = bin_oper->get_right_operand();
45  const auto& lhs_type = lhs->get_type_info();
46  const auto& rhs_type = rhs->get_type_info();
47 
48  if (lhs_type.is_decimal() && rhs_type.is_decimal() && optype == kDIVIDE) {
49  const auto ret = codegenDeciDiv(bin_oper, co);
50  if (ret) {
51  return ret;
52  }
53  }
54 
55  auto lhs_lv = codegen(lhs, true, co).front();
56  auto rhs_lv = codegen(rhs, true, co).front();
57  // Handle operations when a time interval operand is involved, an operation
58  // between an integer and a time interval isn't normalized by the analyzer.
59  if (lhs_type.is_timeinterval()) {
60  rhs_lv = codegenCastBetweenIntTypes(rhs_lv, rhs_type, lhs_type);
61  } else if (rhs_type.is_timeinterval()) {
62  lhs_lv = codegenCastBetweenIntTypes(lhs_lv, lhs_type, rhs_type);
63  } else {
64  CHECK_EQ(lhs_type.get_type(), rhs_type.get_type());
65  }
66  if (lhs_type.is_integer() || lhs_type.is_decimal() || lhs_type.is_timeinterval()) {
67  return codegenIntArith(bin_oper, lhs_lv, rhs_lv, co);
68  }
69  if (lhs_type.is_fp()) {
70  return codegenFpArith(bin_oper, lhs_lv, rhs_lv);
71  }
72  CHECK(false);
73  return nullptr;
74 }
75 
76 // Handle integer or integer-like (decimal, time, date) operand types.
78  llvm::Value* lhs_lv,
79  llvm::Value* rhs_lv,
80  const CompilationOptions& co) {
82  const auto lhs = bin_oper->get_left_operand();
83  const auto rhs = bin_oper->get_right_operand();
84  const auto& lhs_type = lhs->get_type_info();
85  const auto& rhs_type = rhs->get_type_info();
86  const auto int_typename = numeric_or_time_interval_type_name(lhs_type, rhs_type);
87  const auto null_check_suffix = get_null_check_suffix(lhs_type, rhs_type);
88  const auto& oper_type = rhs_type.is_timeinterval() ? rhs_type : lhs_type;
89  switch (bin_oper->get_optype()) {
90  case kMINUS:
91  return codegenSub(bin_oper,
92  lhs_lv,
93  rhs_lv,
94  null_check_suffix.empty() ? "" : int_typename,
95  null_check_suffix,
96  oper_type,
97  co);
98  case kPLUS:
99  return codegenAdd(bin_oper,
100  lhs_lv,
101  rhs_lv,
102  null_check_suffix.empty() ? "" : int_typename,
103  null_check_suffix,
104  oper_type,
105  co);
106  case kMULTIPLY:
107  return codegenMul(bin_oper,
108  lhs_lv,
109  rhs_lv,
110  null_check_suffix.empty() ? "" : int_typename,
111  null_check_suffix,
112  oper_type,
113  co);
114  case kDIVIDE:
115  return codegenDiv(lhs_lv,
116  rhs_lv,
117  null_check_suffix.empty() ? "" : int_typename,
118  null_check_suffix,
119  oper_type);
120  case kMODULO:
121  return codegenMod(lhs_lv,
122  rhs_lv,
123  null_check_suffix.empty() ? "" : int_typename,
124  null_check_suffix,
125  oper_type);
126  default:
127  CHECK(false);
128  }
129  CHECK(false);
130  return nullptr;
131 }
132 
133 // Handle floating point operand types.
135  llvm::Value* lhs_lv,
136  llvm::Value* rhs_lv) {
138  const auto lhs = bin_oper->get_left_operand();
139  const auto rhs = bin_oper->get_right_operand();
140  const auto& lhs_type = lhs->get_type_info();
141  const auto& rhs_type = rhs->get_type_info();
142  const auto fp_typename = numeric_type_name(lhs_type);
143  const auto null_check_suffix = get_null_check_suffix(lhs_type, rhs_type);
144  llvm::ConstantFP* fp_null{lhs_type.get_type() == kFLOAT
147  switch (bin_oper->get_optype()) {
148  case kMINUS:
149  return null_check_suffix.empty()
150  ? cgen_state_->ir_builder_.CreateFSub(lhs_lv, rhs_lv)
151  : cgen_state_->emitCall("sub_" + fp_typename + null_check_suffix,
152  {lhs_lv, rhs_lv, fp_null});
153  case kPLUS:
154  return null_check_suffix.empty()
155  ? cgen_state_->ir_builder_.CreateFAdd(lhs_lv, rhs_lv)
156  : cgen_state_->emitCall("add_" + fp_typename + null_check_suffix,
157  {lhs_lv, rhs_lv, fp_null});
158  case kMULTIPLY:
159  return null_check_suffix.empty()
160  ? cgen_state_->ir_builder_.CreateFMul(lhs_lv, rhs_lv)
161  : cgen_state_->emitCall("mul_" + fp_typename + null_check_suffix,
162  {lhs_lv, rhs_lv, fp_null});
163  case kDIVIDE:
164  return codegenDiv(lhs_lv,
165  rhs_lv,
166  null_check_suffix.empty() ? "" : fp_typename,
167  null_check_suffix,
168  lhs_type);
169  default:
170  CHECK(false);
171  }
172  CHECK(false);
173  return nullptr;
174 }
175 
176 namespace {
177 
179  const auto col_expr = dynamic_cast<const Analyzer::ColumnVar*>(expr);
180  if (!col_expr) {
181  return false;
182  }
183  return col_expr->getColumnKey().table_id < 0;
184 }
185 
186 } // namespace
187 
188 // Returns true iff runtime overflow checks aren't needed thanks to range information.
190  int64_t min,
191  int64_t max) {
192  if (is_temporary_column(bin_oper->get_left_operand()) ||
193  is_temporary_column(bin_oper->get_right_operand())) {
194  // Computing the range for temporary columns is a lot more expensive than the overflow
195  // check.
196  return false;
197  }
198  if (bin_oper->get_type_info().is_decimal()) {
199  return false;
200  }
201 
203  if (executor_) {
204  auto expr_range_info =
205  plan_state_->query_infos_.size() > 0
208  if (expr_range_info.getType() != ExpressionRangeType::Integer) {
209  return false;
210  }
211  if (expr_range_info.getIntMin() >= min && expr_range_info.getIntMax() <= max) {
212  return true;
213  }
214  }
215 
216  return false;
217 }
218 
219 llvm::Value* CodeGenerator::codegenAdd(const Analyzer::BinOper* bin_oper,
220  llvm::Value* lhs_lv,
221  llvm::Value* rhs_lv,
222  const std::string& null_typename,
223  const std::string& null_check_suffix,
224  const SQLTypeInfo& ti,
225  const CompilationOptions& co) {
227  CHECK_EQ(lhs_lv->getType(), rhs_lv->getType());
228  CHECK(ti.is_integer() || ti.is_decimal() || ti.is_timeinterval());
229  llvm::Value* chosen_max{nullptr};
230  llvm::Value* chosen_min{nullptr};
231  std::tie(chosen_max, chosen_min) = cgen_state_->inlineIntMaxMin(ti.get_size(), true);
232  auto need_overflow_check =
233  !checkExpressionRanges(bin_oper,
234  static_cast<llvm::ConstantInt*>(chosen_min)->getSExtValue(),
235  static_cast<llvm::ConstantInt*>(chosen_max)->getSExtValue());
236 
237  if (need_overflow_check && co.device_type == ExecutorDeviceType::CPU) {
239  bin_oper, lhs_lv, rhs_lv, null_check_suffix, ti);
240  }
241 
242  llvm::BasicBlock* add_ok{nullptr};
243  llvm::BasicBlock* add_fail{nullptr};
244  if (need_overflow_check) {
246  add_ok = llvm::BasicBlock::Create(
248  if (!null_check_suffix.empty()) {
249  codegenSkipOverflowCheckForNull(lhs_lv, rhs_lv, add_ok, ti);
250  }
251  add_fail = llvm::BasicBlock::Create(
253  llvm::Value* detected{nullptr};
254  auto const_zero = llvm::ConstantInt::get(lhs_lv->getType(), 0, true);
255  auto overflow = cgen_state_->ir_builder_.CreateAnd(
256  cgen_state_->ir_builder_.CreateICmpSGT(lhs_lv, const_zero),
257  cgen_state_->ir_builder_.CreateICmpSGT(
258  rhs_lv, cgen_state_->ir_builder_.CreateSub(chosen_max, lhs_lv)));
259  auto underflow = cgen_state_->ir_builder_.CreateAnd(
260  cgen_state_->ir_builder_.CreateICmpSLT(lhs_lv, const_zero),
261  cgen_state_->ir_builder_.CreateICmpSLT(
262  rhs_lv, cgen_state_->ir_builder_.CreateSub(chosen_min, lhs_lv)));
263  detected = cgen_state_->ir_builder_.CreateOr(overflow, underflow);
264  cgen_state_->ir_builder_.CreateCondBr(detected, add_fail, add_ok);
265  cgen_state_->ir_builder_.SetInsertPoint(add_ok);
266  }
267  auto ret = null_check_suffix.empty()
268  ? cgen_state_->ir_builder_.CreateAdd(lhs_lv, rhs_lv)
270  "add_" + null_typename + null_check_suffix,
271  {lhs_lv, rhs_lv, cgen_state_->llInt(inline_int_null_val(ti))});
272  if (need_overflow_check) {
273  cgen_state_->ir_builder_.SetInsertPoint(add_fail);
274  cgen_state_->ir_builder_.CreateRet(
275  cgen_state_->llInt(int32_t(ErrorCode::OVERFLOW_OR_UNDERFLOW)));
276  cgen_state_->ir_builder_.SetInsertPoint(add_ok);
277  }
278  return ret;
279 }
280 
281 llvm::Value* CodeGenerator::codegenSub(const Analyzer::BinOper* bin_oper,
282  llvm::Value* lhs_lv,
283  llvm::Value* rhs_lv,
284  const std::string& null_typename,
285  const std::string& null_check_suffix,
286  const SQLTypeInfo& ti,
287  const CompilationOptions& co) {
289  CHECK_EQ(lhs_lv->getType(), rhs_lv->getType());
290  CHECK(ti.is_integer() || ti.is_decimal() || ti.is_timeinterval());
291  llvm::Value* chosen_max{nullptr};
292  llvm::Value* chosen_min{nullptr};
293  std::tie(chosen_max, chosen_min) = cgen_state_->inlineIntMaxMin(ti.get_size(), true);
294  auto need_overflow_check =
295  !checkExpressionRanges(bin_oper,
296  static_cast<llvm::ConstantInt*>(chosen_min)->getSExtValue(),
297  static_cast<llvm::ConstantInt*>(chosen_max)->getSExtValue());
298 
299  if (need_overflow_check && co.device_type == ExecutorDeviceType::CPU) {
301  bin_oper, lhs_lv, rhs_lv, null_check_suffix, ti);
302  }
303 
304  llvm::BasicBlock* sub_ok{nullptr};
305  llvm::BasicBlock* sub_fail{nullptr};
306  if (need_overflow_check) {
308  sub_ok = llvm::BasicBlock::Create(
310  if (!null_check_suffix.empty()) {
311  codegenSkipOverflowCheckForNull(lhs_lv, rhs_lv, sub_ok, ti);
312  }
313  sub_fail = llvm::BasicBlock::Create(
315  llvm::Value* detected{nullptr};
316  auto const_zero = llvm::ConstantInt::get(lhs_lv->getType(), 0, true);
317  auto overflow = cgen_state_->ir_builder_.CreateAnd(
318  cgen_state_->ir_builder_.CreateICmpSLT(
319  rhs_lv, const_zero), // sub going up, check the max
320  cgen_state_->ir_builder_.CreateICmpSGT(
321  lhs_lv, cgen_state_->ir_builder_.CreateAdd(chosen_max, rhs_lv)));
322  auto underflow = cgen_state_->ir_builder_.CreateAnd(
323  cgen_state_->ir_builder_.CreateICmpSGT(
324  rhs_lv, const_zero), // sub going down, check the min
325  cgen_state_->ir_builder_.CreateICmpSLT(
326  lhs_lv, cgen_state_->ir_builder_.CreateAdd(chosen_min, rhs_lv)));
327  detected = cgen_state_->ir_builder_.CreateOr(overflow, underflow);
328  cgen_state_->ir_builder_.CreateCondBr(detected, sub_fail, sub_ok);
329  cgen_state_->ir_builder_.SetInsertPoint(sub_ok);
330  }
331  auto ret = null_check_suffix.empty()
332  ? cgen_state_->ir_builder_.CreateSub(lhs_lv, rhs_lv)
334  "sub_" + null_typename + null_check_suffix,
335  {lhs_lv, rhs_lv, cgen_state_->llInt(inline_int_null_val(ti))});
336  if (need_overflow_check) {
337  cgen_state_->ir_builder_.SetInsertPoint(sub_fail);
338  cgen_state_->ir_builder_.CreateRet(
339  cgen_state_->llInt(int32_t(ErrorCode::OVERFLOW_OR_UNDERFLOW)));
340  cgen_state_->ir_builder_.SetInsertPoint(sub_ok);
341  }
342  return ret;
343 }
344 
346  llvm::Value* rhs_lv,
347  llvm::BasicBlock* no_overflow_bb,
348  const SQLTypeInfo& ti) {
349  const auto lhs_is_null_lv = codegenIsNullNumber(lhs_lv, ti);
350  const auto has_null_operand_lv =
351  rhs_lv ? cgen_state_->ir_builder_.CreateOr(lhs_is_null_lv,
352  codegenIsNullNumber(rhs_lv, ti))
353  : lhs_is_null_lv;
354  auto operands_not_null = llvm::BasicBlock::Create(
355  cgen_state_->context_, "operands_not_null", cgen_state_->current_func_);
356  cgen_state_->ir_builder_.CreateCondBr(
357  has_null_operand_lv, no_overflow_bb, operands_not_null);
358  cgen_state_->ir_builder_.SetInsertPoint(operands_not_null);
359 }
360 
361 llvm::Value* CodeGenerator::codegenMul(const Analyzer::BinOper* bin_oper,
362  llvm::Value* lhs_lv,
363  llvm::Value* rhs_lv,
364  const std::string& null_typename,
365  const std::string& null_check_suffix,
366  const SQLTypeInfo& ti,
367  const CompilationOptions& co,
368  bool downscale) {
370  CHECK_EQ(lhs_lv->getType(), rhs_lv->getType());
371  CHECK(ti.is_integer() || ti.is_decimal() || ti.is_timeinterval());
372  llvm::Value* chosen_max{nullptr};
373  llvm::Value* chosen_min{nullptr};
374  std::tie(chosen_max, chosen_min) = cgen_state_->inlineIntMaxMin(ti.get_size(), true);
375  auto need_overflow_check =
376  !checkExpressionRanges(bin_oper,
377  static_cast<llvm::ConstantInt*>(chosen_min)->getSExtValue(),
378  static_cast<llvm::ConstantInt*>(chosen_max)->getSExtValue());
379 
380  if (need_overflow_check && co.device_type == ExecutorDeviceType::CPU) {
382  bin_oper, lhs_lv, rhs_lv, null_check_suffix, ti);
383  }
384 
385  llvm::BasicBlock* mul_ok{nullptr};
386  llvm::BasicBlock* mul_fail{nullptr};
387  if (need_overflow_check) {
389  mul_ok = llvm::BasicBlock::Create(
391  if (!null_check_suffix.empty()) {
392  codegenSkipOverflowCheckForNull(lhs_lv, rhs_lv, mul_ok, ti);
393  }
394  mul_fail = llvm::BasicBlock::Create(
396  auto mul_check = llvm::BasicBlock::Create(
398  auto const_zero = llvm::ConstantInt::get(rhs_lv->getType(), 0, true);
399  cgen_state_->ir_builder_.CreateCondBr(
400  cgen_state_->ir_builder_.CreateICmpEQ(rhs_lv, const_zero), mul_ok, mul_check);
401  cgen_state_->ir_builder_.SetInsertPoint(mul_check);
402  auto rhs_is_negative_lv = cgen_state_->ir_builder_.CreateICmpSLT(rhs_lv, const_zero);
403  auto positive_rhs_lv = cgen_state_->ir_builder_.CreateSelect(
404  rhs_is_negative_lv, cgen_state_->ir_builder_.CreateNeg(rhs_lv), rhs_lv);
405  auto adjusted_lhs_lv = cgen_state_->ir_builder_.CreateSelect(
406  rhs_is_negative_lv, cgen_state_->ir_builder_.CreateNeg(lhs_lv), lhs_lv);
407  auto detected = cgen_state_->ir_builder_.CreateOr( // overflow
408  cgen_state_->ir_builder_.CreateICmpSGT(
409  adjusted_lhs_lv,
410  cgen_state_->ir_builder_.CreateSDiv(chosen_max, positive_rhs_lv)),
411  // underflow
412  cgen_state_->ir_builder_.CreateICmpSLT(
413  adjusted_lhs_lv,
414  cgen_state_->ir_builder_.CreateSDiv(chosen_min, positive_rhs_lv)));
415  cgen_state_->ir_builder_.CreateCondBr(detected, mul_fail, mul_ok);
416  cgen_state_->ir_builder_.SetInsertPoint(mul_ok);
417  }
418  const auto ret =
419  null_check_suffix.empty()
420  ? cgen_state_->ir_builder_.CreateMul(lhs_lv, rhs_lv)
422  "mul_" + null_typename + null_check_suffix,
423  {lhs_lv, rhs_lv, cgen_state_->llInt(inline_int_null_val(ti))});
424  if (need_overflow_check) {
425  cgen_state_->ir_builder_.SetInsertPoint(mul_fail);
426  cgen_state_->ir_builder_.CreateRet(
427  cgen_state_->llInt(int32_t(ErrorCode::OVERFLOW_OR_UNDERFLOW)));
428  cgen_state_->ir_builder_.SetInsertPoint(mul_ok);
429  }
430  return ret;
431 }
432 
433 llvm::Value* CodeGenerator::codegenDiv(llvm::Value* lhs_lv,
434  llvm::Value* rhs_lv,
435  const std::string& null_typename,
436  const std::string& null_check_suffix,
437  const SQLTypeInfo& ti,
438  bool upscale) {
440  CHECK_EQ(lhs_lv->getType(), rhs_lv->getType());
441  if (ti.is_decimal()) {
442  if (upscale) {
443  CHECK(lhs_lv->getType()->isIntegerTy());
444  const auto scale_lv =
445  llvm::ConstantInt::get(lhs_lv->getType(), exp_to_scale(ti.get_scale()));
446 
447  lhs_lv = cgen_state_->ir_builder_.CreateSExt(
448  lhs_lv, get_int_type(64, cgen_state_->context_));
449  llvm::Value* chosen_max{nullptr};
450  llvm::Value* chosen_min{nullptr};
451  std::tie(chosen_max, chosen_min) = cgen_state_->inlineIntMaxMin(8, true);
452  auto decimal_div_ok = llvm::BasicBlock::Create(
453  cgen_state_->context_, "decimal_div_ok", cgen_state_->current_func_);
454  if (!null_check_suffix.empty()) {
455  codegenSkipOverflowCheckForNull(lhs_lv, rhs_lv, decimal_div_ok, ti);
456  }
457  auto decimal_div_fail = llvm::BasicBlock::Create(
458  cgen_state_->context_, "decimal_div_fail", cgen_state_->current_func_);
459  auto lhs_max = static_cast<llvm::ConstantInt*>(chosen_max)->getSExtValue() /
460  exp_to_scale(ti.get_scale());
461  auto lhs_max_lv =
462  llvm::ConstantInt::get(get_int_type(64, cgen_state_->context_), lhs_max);
463  llvm::Value* detected{nullptr};
464  if (ti.get_notnull()) {
465  detected = cgen_state_->ir_builder_.CreateICmpSGT(lhs_lv, lhs_max_lv);
466  } else {
467  detected = toBool(cgen_state_->emitCall(
468  "gt_" + numeric_type_name(ti) + "_nullable",
469  {lhs_lv,
470  lhs_max_lv,
473  }
474  cgen_state_->ir_builder_.CreateCondBr(detected, decimal_div_fail, decimal_div_ok);
475 
476  cgen_state_->ir_builder_.SetInsertPoint(decimal_div_fail);
477  cgen_state_->ir_builder_.CreateRet(
478  cgen_state_->llInt(int32_t(ErrorCode::OVERFLOW_OR_UNDERFLOW)));
479 
480  cgen_state_->ir_builder_.SetInsertPoint(decimal_div_ok);
481 
482  lhs_lv = null_typename.empty()
483  ? cgen_state_->ir_builder_.CreateMul(lhs_lv, scale_lv)
485  "mul_" + numeric_type_name(ti) + null_check_suffix,
486  {lhs_lv, scale_lv, cgen_state_->llInt(inline_int_null_val(ti))});
487  }
488  }
489  if (g_null_div_by_zero) {
490  llvm::Value* null_lv{nullptr};
491  if (ti.is_fp()) {
492  null_lv = ti.get_type() == kFLOAT ? cgen_state_->llFp(NULL_FLOAT)
494  } else {
495  null_lv = cgen_state_->llInt(inline_int_null_val(ti));
496  }
497  return cgen_state_->emitCall("safe_div_" + numeric_type_name(ti),
498  {lhs_lv, rhs_lv, null_lv});
499  }
501  auto div_ok = llvm::BasicBlock::Create(
503  if (!null_check_suffix.empty()) {
504  codegenSkipOverflowCheckForNull(lhs_lv, rhs_lv, div_ok, ti);
505  }
506  auto div_zero = llvm::BasicBlock::Create(
508  auto zero_const = rhs_lv->getType()->isIntegerTy()
509  ? llvm::ConstantInt::get(rhs_lv->getType(), 0, true)
510  : llvm::ConstantFP::get(rhs_lv->getType(), 0.);
511  cgen_state_->ir_builder_.CreateCondBr(
512  zero_const->getType()->isFloatingPointTy()
513  ? cgen_state_->ir_builder_.CreateFCmp(
514  llvm::FCmpInst::FCMP_ONE, rhs_lv, zero_const)
515  : cgen_state_->ir_builder_.CreateICmp(
516  llvm::ICmpInst::ICMP_NE, rhs_lv, zero_const),
517  div_ok,
518  div_zero);
519  cgen_state_->ir_builder_.SetInsertPoint(div_ok);
520  auto ret =
521  zero_const->getType()->isIntegerTy()
522  ? (null_typename.empty()
523  ? cgen_state_->ir_builder_.CreateSDiv(lhs_lv, rhs_lv)
525  "div_" + null_typename + null_check_suffix,
526  {lhs_lv, rhs_lv, cgen_state_->llInt(inline_int_null_val(ti))}))
527  : (null_typename.empty()
528  ? cgen_state_->ir_builder_.CreateFDiv(lhs_lv, rhs_lv)
530  "div_" + null_typename + null_check_suffix,
531  {lhs_lv,
532  rhs_lv,
535  cgen_state_->ir_builder_.SetInsertPoint(div_zero);
536  cgen_state_->ir_builder_.CreateRet(cgen_state_->llInt(int32_t(ErrorCode::DIV_BY_ZERO)));
537  cgen_state_->ir_builder_.SetInsertPoint(div_ok);
538  return ret;
539 }
540 
541 // Handle decimal division by an integer (constant or cast), return null if
542 // the expression doesn't match this pattern and let the general method kick in.
543 // For said patterns, we can simply divide the decimal operand by the non-scaled
544 // integer value instead of using the scaled value preceded by a multiplication.
545 // It is both more efficient and avoids the overflow for a lot of practical cases.
547  const CompilationOptions& co) {
549  auto lhs = bin_oper->get_left_operand();
550  auto rhs = bin_oper->get_right_operand();
551  const auto& lhs_type = lhs->get_type_info();
552  const auto& rhs_type = rhs->get_type_info();
553  CHECK(lhs_type.is_decimal() && rhs_type.is_decimal() &&
554  lhs_type.get_scale() == rhs_type.get_scale());
555 
556  auto rhs_constant = dynamic_cast<const Analyzer::Constant*>(rhs);
557  auto rhs_cast = dynamic_cast<const Analyzer::UOper*>(rhs);
558  if (rhs_constant && !rhs_constant->get_is_null() &&
559  rhs_constant->get_constval().bigintval != 0LL &&
560  (rhs_constant->get_constval().bigintval % exp_to_scale(rhs_type.get_scale())) ==
561  0LL) {
562  // can safely downscale a scaled constant
563  } else if (rhs_cast && rhs_cast->get_optype() == kCAST &&
564  rhs_cast->get_operand()->get_type_info().is_integer()) {
565  // can skip upscale in the int to dec cast
566  } else {
567  return nullptr;
568  }
569 
570  auto lhs_lv = codegen(lhs, true, co).front();
571  llvm::Value* rhs_lv{nullptr};
572  if (rhs_constant) {
573  const auto rhs_lit = Parser::IntLiteral::analyzeValue(
574  rhs_constant->get_constval().bigintval / exp_to_scale(rhs_type.get_scale()));
575  auto rhs_lit_lv = CodeGenerator::codegenIntConst(
576  dynamic_cast<const Analyzer::Constant*>(rhs_lit.get()), cgen_state_);
578  rhs_lit_lv, rhs_lit->get_type_info(), lhs_type, /*upscale*/ false);
579  } else if (rhs_cast) {
580  auto rhs_cast_oper = rhs_cast->get_operand();
581  const auto& rhs_cast_oper_ti = rhs_cast_oper->get_type_info();
582  auto rhs_cast_oper_lv = codegen(rhs_cast_oper, true, co).front();
584  rhs_cast_oper_lv, rhs_cast_oper_ti, lhs_type, /*upscale*/ false);
585  } else {
586  CHECK(false);
587  }
588  const auto int_typename = numeric_or_time_interval_type_name(lhs_type, rhs_type);
589  const auto null_check_suffix = get_null_check_suffix(lhs_type, rhs_type);
590  return codegenDiv(lhs_lv,
591  rhs_lv,
592  null_check_suffix.empty() ? "" : int_typename,
593  null_check_suffix,
594  lhs_type,
595  /*upscale*/ false);
596 }
597 
598 llvm::Value* CodeGenerator::codegenMod(llvm::Value* lhs_lv,
599  llvm::Value* rhs_lv,
600  const std::string& null_typename,
601  const std::string& null_check_suffix,
602  const SQLTypeInfo& ti) {
604  CHECK_EQ(lhs_lv->getType(), rhs_lv->getType());
605  CHECK(ti.is_integer());
607  // Generate control flow for division by zero error handling.
608  auto mod_ok = llvm::BasicBlock::Create(
610  auto mod_zero = llvm::BasicBlock::Create(
612  auto zero_const = llvm::ConstantInt::get(rhs_lv->getType(), 0, true);
613  cgen_state_->ir_builder_.CreateCondBr(
614  cgen_state_->ir_builder_.CreateICmp(llvm::ICmpInst::ICMP_NE, rhs_lv, zero_const),
615  mod_ok,
616  mod_zero);
617  cgen_state_->ir_builder_.SetInsertPoint(mod_ok);
618  auto ret = null_typename.empty()
619  ? cgen_state_->ir_builder_.CreateSRem(lhs_lv, rhs_lv)
621  "mod_" + null_typename + null_check_suffix,
622  {lhs_lv, rhs_lv, cgen_state_->llInt(inline_int_null_val(ti))});
623  cgen_state_->ir_builder_.SetInsertPoint(mod_zero);
624  cgen_state_->ir_builder_.CreateRet(cgen_state_->llInt(int32_t(ErrorCode::DIV_BY_ZERO)));
625  cgen_state_->ir_builder_.SetInsertPoint(mod_ok);
626  return ret;
627 }
628 
629 // Returns true iff runtime overflow checks aren't needed thanks to range information.
631  int64_t min,
632  int64_t max) {
633  if (uoper->get_type_info().is_decimal()) {
634  return false;
635  }
636 
638  if (executor_) {
639  auto expr_range_info =
640  plan_state_->query_infos_.size() > 0
643  if (expr_range_info.getType() != ExpressionRangeType::Integer) {
644  return false;
645  }
646  if (expr_range_info.getIntMin() >= min && expr_range_info.getIntMax() <= max) {
647  return true;
648  }
649  }
650 
651  return false;
652 }
653 
655  const CompilationOptions& co) {
657  CHECK_EQ(uoper->get_optype(), kUMINUS);
658  const auto operand_lv = codegen(uoper->get_operand(), true, co).front();
659  const auto& ti = uoper->get_type_info();
660  llvm::Value* chosen_max{nullptr};
661  llvm::Value* chosen_min{nullptr};
662  bool need_overflow_check = false;
663  if (ti.is_integer() || ti.is_decimal() || ti.is_timeinterval()) {
664  std::tie(chosen_max, chosen_min) = cgen_state_->inlineIntMaxMin(ti.get_size(), true);
665  need_overflow_check = !checkExpressionRanges(
666  uoper,
667  static_cast<llvm::ConstantInt*>(chosen_min)->getSExtValue(),
668  static_cast<llvm::ConstantInt*>(chosen_max)->getSExtValue());
669  }
670  llvm::BasicBlock* uminus_ok{nullptr};
671  llvm::BasicBlock* uminus_fail{nullptr};
672  if (need_overflow_check) {
674  uminus_ok = llvm::BasicBlock::Create(
676  if (!ti.get_notnull()) {
677  codegenSkipOverflowCheckForNull(operand_lv, nullptr, uminus_ok, ti);
678  }
679  uminus_fail = llvm::BasicBlock::Create(
680  cgen_state_->context_, "uminus_fail", cgen_state_->current_func_);
681  auto const_min = llvm::ConstantInt::get(
682  operand_lv->getType(),
683  static_cast<llvm::ConstantInt*>(chosen_min)->getSExtValue(),
684  true);
685  auto overflow = cgen_state_->ir_builder_.CreateICmpEQ(operand_lv, const_min);
686  cgen_state_->ir_builder_.CreateCondBr(overflow, uminus_fail, uminus_ok);
687  cgen_state_->ir_builder_.SetInsertPoint(uminus_ok);
688  }
689  auto ret =
690  ti.get_notnull()
691  ? (ti.is_fp() ? cgen_state_->ir_builder_.CreateFNeg(operand_lv)
692  : cgen_state_->ir_builder_.CreateNeg(operand_lv))
694  "uminus_" + numeric_type_name(ti) + "_nullable",
695  {operand_lv,
696  ti.is_fp() ? static_cast<llvm::Value*>(cgen_state_->inlineFpNull(ti))
697  : static_cast<llvm::Value*>(cgen_state_->inlineIntNull(ti))});
698  if (need_overflow_check) {
699  cgen_state_->ir_builder_.SetInsertPoint(uminus_fail);
700  cgen_state_->ir_builder_.CreateRet(
701  cgen_state_->llInt(int32_t(ErrorCode::OVERFLOW_OR_UNDERFLOW)));
702  cgen_state_->ir_builder_.SetInsertPoint(uminus_ok);
703  }
704  return ret;
705 }
706 
708  const Analyzer::BinOper* bin_oper,
709  llvm::Type* type) {
710  llvm::Intrinsic::ID fn_id{llvm::Intrinsic::not_intrinsic};
711  switch (bin_oper->get_optype()) {
712  case kMINUS:
713  fn_id = llvm::Intrinsic::ssub_with_overflow;
714  break;
715  case kPLUS:
716  fn_id = llvm::Intrinsic::sadd_with_overflow;
717  break;
718  case kMULTIPLY:
719  fn_id = llvm::Intrinsic::smul_with_overflow;
720  break;
721  default:
722  LOG(FATAL) << "unexpected arith with overflow optype: " << bin_oper->toString();
723  }
724 
725  return llvm::Intrinsic::getDeclaration(cgen_state_->module_, fn_id, type);
726 }
727 
729  const Analyzer::BinOper* bin_oper,
730  llvm::Value* lhs_lv,
731  llvm::Value* rhs_lv,
732  const std::string& null_check_suffix,
733  const SQLTypeInfo& ti) {
736 
737  llvm::BasicBlock* check_ok = llvm::BasicBlock::Create(
739  llvm::BasicBlock* check_fail = llvm::BasicBlock::Create(
740  cgen_state_->context_, "ovf_detected", cgen_state_->current_func_);
741  llvm::BasicBlock* null_check{nullptr};
742 
743  if (!null_check_suffix.empty()) {
744  null_check = cgen_state_->ir_builder_.GetInsertBlock();
745  codegenSkipOverflowCheckForNull(lhs_lv, rhs_lv, check_ok, ti);
746  }
747 
748  // Compute result and overflow flag
749  auto func = getArithWithOverflowIntrinsic(bin_oper, lhs_lv->getType());
750  auto ret_and_overflow = cgen_state_->ir_builder_.CreateCall(
751  func, std::vector<llvm::Value*>{lhs_lv, rhs_lv});
752  auto ret = cgen_state_->ir_builder_.CreateExtractValue(ret_and_overflow,
753  std::vector<unsigned>{0});
754  auto overflow = cgen_state_->ir_builder_.CreateExtractValue(ret_and_overflow,
755  std::vector<unsigned>{1});
756  auto val_bb = cgen_state_->ir_builder_.GetInsertBlock();
757 
758  // Return error on overflow
759  cgen_state_->ir_builder_.CreateCondBr(overflow, check_fail, check_ok);
760  cgen_state_->ir_builder_.SetInsertPoint(check_fail);
761  cgen_state_->ir_builder_.CreateRet(
762  cgen_state_->llInt(int32_t(ErrorCode::OVERFLOW_OR_UNDERFLOW)));
763 
764  cgen_state_->ir_builder_.SetInsertPoint(check_ok);
765 
766  // In case of null check we have to use NULL result on check fail
767  if (null_check) {
768  auto phi = cgen_state_->ir_builder_.CreatePHI(ret->getType(), 2);
769  phi->addIncoming(llvm::ConstantInt::get(ret->getType(), inline_int_null_val(ti)),
770  null_check);
771  phi->addIncoming(ret, val_bb);
772  ret = phi;
773  }
774 
775  return ret;
776 }
llvm::Value * codegenIntArith(const Analyzer::BinOper *, llvm::Value *, llvm::Value *, const CompilationOptions &)
#define CHECK_EQ(x, y)
Definition: Logger.h:301
#define NULL_DOUBLE
HOST DEVICE int get_size() const
Definition: sqltypes.h:403
llvm::Value * codegenArith(const Analyzer::BinOper *, const CompilationOptions &)
CgenState * cgen_state_
#define NULL_FLOAT
static std::shared_ptr< Analyzer::Expr > analyzeValue(const int64_t intval)
Definition: ParserNode.cpp:166
#define LOG(tag)
Definition: Logger.h:285
bool is_fp() const
Definition: sqltypes.h:573
HOST DEVICE int get_scale() const
Definition: sqltypes.h:396
const Expr * get_right_operand() const
Definition: Analyzer.h:456
llvm::Value * codegenMod(llvm::Value *, llvm::Value *, const std::string &null_typename, const std::string &null_check_suffix, const SQLTypeInfo &)
llvm::IRBuilder ir_builder_
Definition: CgenState.h:384
Definition: sqldefs.h:51
Definition: sqldefs.h:43
llvm::Value * codegenDeciDiv(const Analyzer::BinOper *, const CompilationOptions &)
HOST DEVICE SQLTypes get_type() const
Definition: sqltypes.h:391
llvm::Type * get_int_type(const int width, llvm::LLVMContext &context)
std::string toString() const override
Definition: Analyzer.cpp:2786
llvm::Value * codegenFpArith(const Analyzer::BinOper *, llvm::Value *, llvm::Value *)
bool g_null_div_by_zero
Definition: Execute.cpp:95
SQLOps get_optype() const
Definition: Analyzer.h:452
llvm::Module * module_
Definition: CgenState.h:373
llvm::LLVMContext & context_
Definition: CgenState.h:382
llvm::Function * current_func_
Definition: CgenState.h:376
llvm::Value * codegenDiv(llvm::Value *, llvm::Value *, const std::string &null_typename, const std::string &null_check_suffix, const SQLTypeInfo &, bool upscale=true)
std::string numeric_or_time_interval_type_name(const SQLTypeInfo &ti1, const SQLTypeInfo &ti2)
Classes representing a parse tree.
bool is_integer() const
Definition: sqltypes.h:567
bool is_temporary_column(const Analyzer::Expr *expr)
void codegenSkipOverflowCheckForNull(llvm::Value *lhs_lv, llvm::Value *rhs_lv, llvm::BasicBlock *no_overflow_bb, const SQLTypeInfo &ti)
llvm::ConstantInt * inlineIntNull(const SQLTypeInfo &)
Definition: CgenState.cpp:65
llvm::Value * codegenBinOpWithOverflowForCPU(const Analyzer::BinOper *bin_oper, llvm::Value *lhs_lv, llvm::Value *rhs_lv, const std::string &null_check_suffix, const SQLTypeInfo &ti)
bool is_timeinterval() const
Definition: sqltypes.h:594
llvm::Value * codegenCastBetweenIntTypes(llvm::Value *operand_lv, const SQLTypeInfo &operand_ti, const SQLTypeInfo &ti, bool upscale=true)
Definition: CastIR.cpp:427
Executor * executor_
const std::vector< InputTableInfo > & query_infos_
Definition: PlanState.h:65
bool needs_error_check_
Definition: CgenState.h:405
llvm::ConstantFP * llFp(const float v) const
Definition: CgenState.h:253
ExpressionRange getExpressionRange(const Analyzer::BinOper *expr, const std::vector< InputTableInfo > &query_infos, const Executor *, boost::optional< std::list< std::shared_ptr< Analyzer::Expr >>> simple_quals)
#define AUTOMATIC_IR_METADATA(CGENSTATE)
llvm::Function * getArithWithOverflowIntrinsic(const Analyzer::BinOper *bin_oper, llvm::Type *type)
std::string get_null_check_suffix(const SQLTypeInfo &lhs_ti, const SQLTypeInfo &rhs_ti)
Definition: Execute.h:1661
const SQLTypeInfo & get_type_info() const
Definition: Analyzer.h:79
llvm::Value * codegenUMinus(const Analyzer::UOper *, const CompilationOptions &)
llvm::Value * emitCall(const std::string &fname, const std::vector< llvm::Value * > &args)
Definition: CgenState.cpp:217
ExecutorDeviceType device_type
PlanState * plan_state_
std::vector< llvm::Value * > codegen(const Analyzer::Expr *, const bool fetch_columns, const CompilationOptions &)
Definition: IRCodegen.cpp:30
static llvm::ConstantInt * codegenIntConst(const Analyzer::Constant *constant, CgenState *cgen_state)
Definition: ConstantIR.cpp:89
Definition: sqldefs.h:42
const shared::ColumnKey & getColumnKey() const
Definition: Analyzer.h:198
#define IS_ARITHMETIC(X)
Definition: sqldefs.h:65
const Expr * get_operand() const
Definition: Analyzer.h:384
llvm::Value * codegenSub(const Analyzer::BinOper *, llvm::Value *, llvm::Value *, const std::string &null_typename, const std::string &null_check_suffix, const SQLTypeInfo &, const CompilationOptions &)
llvm::Value * toBool(llvm::Value *)
Definition: LogicalIR.cpp:344
llvm::ConstantInt * llInt(const T v) const
Definition: CgenState.h:249
#define CHECK(condition)
Definition: Logger.h:291
llvm::Value * codegenIsNullNumber(llvm::Value *, const SQLTypeInfo &)
Definition: LogicalIR.cpp:416
uint64_t exp_to_scale(const unsigned exp)
int64_t inline_int_null_val(const SQL_TYPE_INFO &ti)
const Expr * get_left_operand() const
Definition: Analyzer.h:455
std::string numeric_type_name(const SQLTypeInfo &ti)
Definition: Execute.h:230
static ExpressionRange makeInvalidRange()
llvm::Value * codegenMul(const Analyzer::BinOper *, llvm::Value *, llvm::Value *, const std::string &null_typename, const std::string &null_check_suffix, const SQLTypeInfo &, const CompilationOptions &, bool downscale=true)
HOST DEVICE bool get_notnull() const
Definition: sqltypes.h:398
llvm::Value * codegenAdd(const Analyzer::BinOper *, llvm::Value *, llvm::Value *, const std::string &null_typename, const std::string &null_check_suffix, const SQLTypeInfo &, const CompilationOptions &)
bool checkExpressionRanges(const Analyzer::UOper *, int64_t, int64_t)
bool is_decimal() const
Definition: sqltypes.h:570
std::pair< llvm::ConstantInt *, llvm::ConstantInt * > inlineIntMaxMin(const size_t byte_width, const bool is_signed)
Definition: CgenState.cpp:121
SQLOps get_optype() const
Definition: Analyzer.h:383
llvm::ConstantFP * inlineFpNull(const SQLTypeInfo &)
Definition: CgenState.cpp:104
Executor * executor() const