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