24 using heavyai::ErrorCode;
46 const auto& rhs_type = rhs->get_type_info();
48 if (lhs_type.is_decimal() && rhs_type.is_decimal() && optype ==
kDIVIDE) {
55 auto lhs_lv =
codegen(lhs,
true, co).front();
56 auto rhs_lv =
codegen(rhs,
true, co).front();
59 if (lhs_type.is_timeinterval()) {
61 }
else if (rhs_type.is_timeinterval()) {
64 CHECK_EQ(lhs_type.get_type(), rhs_type.get_type());
66 if (lhs_type.is_integer() || lhs_type.is_decimal() || lhs_type.is_timeinterval()) {
69 if (lhs_type.is_fp()) {
85 const auto& rhs_type = rhs->get_type_info();
88 const auto& oper_type = rhs_type.is_timeinterval() ? rhs_type : lhs_type;
94 null_check_suffix.empty() ?
"" : int_typename,
102 null_check_suffix.empty() ?
"" : int_typename,
110 null_check_suffix.empty() ?
"" : int_typename,
117 null_check_suffix.empty() ?
"" : int_typename,
123 null_check_suffix.empty() ?
"" : int_typename,
136 llvm::Value* rhs_lv) {
141 const auto& rhs_type = rhs->get_type_info();
144 llvm::ConstantFP* fp_null{lhs_type.get_type() ==
kFLOAT
149 return null_check_suffix.empty()
152 {lhs_lv, rhs_lv, fp_null});
154 return null_check_suffix.empty()
157 {lhs_lv, rhs_lv, fp_null});
159 return null_check_suffix.empty()
162 {lhs_lv, rhs_lv, fp_null});
166 null_check_suffix.empty() ?
"" : fp_typename,
204 auto expr_range_info =
211 if (expr_range_info.getIntMin() >= min && expr_range_info.getIntMax() <= max) {
222 const std::string& null_typename,
223 const std::string& null_check_suffix,
227 CHECK_EQ(lhs_lv->getType(), rhs_lv->getType());
229 llvm::Value* chosen_max{
nullptr};
230 llvm::Value* chosen_min{
nullptr};
232 auto need_overflow_check =
234 static_cast<llvm::ConstantInt*>(chosen_min)->getSExtValue(),
235 static_cast<llvm::ConstantInt*>(chosen_max)->getSExtValue());
239 bin_oper, lhs_lv, rhs_lv, null_check_suffix, ti);
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()) {
251 add_fail = llvm::BasicBlock::Create(
253 llvm::Value* detected{
nullptr};
254 auto const_zero = llvm::ConstantInt::get(lhs_lv->getType(), 0,
true);
267 auto ret = null_check_suffix.empty()
270 "add_" + null_typename + null_check_suffix,
272 if (need_overflow_check) {
284 const std::string& null_typename,
285 const std::string& null_check_suffix,
289 CHECK_EQ(lhs_lv->getType(), rhs_lv->getType());
291 llvm::Value* chosen_max{
nullptr};
292 llvm::Value* chosen_min{
nullptr};
294 auto need_overflow_check =
296 static_cast<llvm::ConstantInt*>(chosen_min)->getSExtValue(),
297 static_cast<llvm::ConstantInt*>(chosen_max)->getSExtValue());
301 bin_oper, lhs_lv, rhs_lv, null_check_suffix, ti);
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()) {
313 sub_fail = llvm::BasicBlock::Create(
315 llvm::Value* detected{
nullptr};
316 auto const_zero = llvm::ConstantInt::get(lhs_lv->getType(), 0,
true);
331 auto ret = null_check_suffix.empty()
334 "sub_" + null_typename + null_check_suffix,
336 if (need_overflow_check) {
347 llvm::BasicBlock* no_overflow_bb,
350 const auto has_null_operand_lv =
354 auto operands_not_null = llvm::BasicBlock::Create(
357 has_null_operand_lv, no_overflow_bb, operands_not_null);
364 const std::string& null_typename,
365 const std::string& null_check_suffix,
370 CHECK_EQ(lhs_lv->getType(), rhs_lv->getType());
372 llvm::Value* chosen_max{
nullptr};
373 llvm::Value* chosen_min{
nullptr};
375 auto need_overflow_check =
377 static_cast<llvm::ConstantInt*>(chosen_min)->getSExtValue(),
378 static_cast<llvm::ConstantInt*>(chosen_max)->getSExtValue());
382 bin_oper, lhs_lv, rhs_lv, null_check_suffix, ti);
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()) {
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);
419 null_check_suffix.empty()
422 "mul_" + null_typename + null_check_suffix,
424 if (need_overflow_check) {
435 const std::string& null_typename,
436 const std::string& null_check_suffix,
440 CHECK_EQ(lhs_lv->getType(), rhs_lv->getType());
443 CHECK(lhs_lv->getType()->isIntegerTy());
444 const auto scale_lv =
449 llvm::Value* chosen_max{
nullptr};
450 llvm::Value* chosen_min{
nullptr};
452 auto decimal_div_ok = llvm::BasicBlock::Create(
454 if (!null_check_suffix.empty()) {
457 auto decimal_div_fail = llvm::BasicBlock::Create(
459 auto lhs_max =
static_cast<llvm::ConstantInt*
>(chosen_max)->getSExtValue() /
463 llvm::Value* detected{
nullptr};
482 lhs_lv = null_typename.empty()
490 llvm::Value* null_lv{
nullptr};
498 {lhs_lv, rhs_lv, null_lv});
501 auto div_ok = llvm::BasicBlock::Create(
503 if (!null_check_suffix.empty()) {
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.);
512 zero_const->getType()->isFloatingPointTy()
514 llvm::FCmpInst::FCMP_ONE, rhs_lv, zero_const)
516 llvm::ICmpInst::ICMP_NE, rhs_lv, zero_const),
521 zero_const->getType()->isIntegerTy()
522 ? (null_typename.empty()
525 "div_" + null_typename + null_check_suffix,
527 : (null_typename.empty()
530 "div_" + null_typename + null_check_suffix,
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());
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())) ==
563 }
else if (rhs_cast && rhs_cast->get_optype() ==
kCAST &&
564 rhs_cast->get_operand()->get_type_info().is_integer()) {
570 auto lhs_lv =
codegen(lhs,
true, co).front();
571 llvm::Value* rhs_lv{
nullptr};
574 rhs_constant->get_constval().bigintval /
exp_to_scale(rhs_type.get_scale()));
576 dynamic_cast<const Analyzer::Constant*>(rhs_lit.get()),
cgen_state_);
578 rhs_lit_lv, rhs_lit->get_type_info(), lhs_type,
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,
false);
592 null_check_suffix.empty() ?
"" : int_typename,
600 const std::string& null_typename,
601 const std::string& null_check_suffix,
604 CHECK_EQ(lhs_lv->getType(), rhs_lv->getType());
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);
618 auto ret = null_typename.empty()
621 "mod_" + null_typename + null_check_suffix,
639 auto expr_range_info =
646 if (expr_range_info.getIntMin() >= min && expr_range_info.getIntMax() <= max) {
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()) {
667 static_cast<llvm::ConstantInt*>(chosen_min)->getSExtValue(),
668 static_cast<llvm::ConstantInt*>(chosen_max)->getSExtValue());
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()) {
679 uminus_fail = llvm::BasicBlock::Create(
681 auto const_min = llvm::ConstantInt::get(
682 operand_lv->getType(),
683 static_cast<llvm::ConstantInt*
>(chosen_min)->getSExtValue(),
698 if (need_overflow_check) {
710 llvm::Intrinsic::ID fn_id{llvm::Intrinsic::not_intrinsic};
713 fn_id = llvm::Intrinsic::ssub_with_overflow;
716 fn_id = llvm::Intrinsic::sadd_with_overflow;
719 fn_id = llvm::Intrinsic::smul_with_overflow;
722 LOG(
FATAL) <<
"unexpected arith with overflow optype: " << bin_oper->
toString();
732 const std::string& null_check_suffix,
737 llvm::BasicBlock* check_ok = llvm::BasicBlock::Create(
739 llvm::BasicBlock* check_fail = llvm::BasicBlock::Create(
741 llvm::BasicBlock* null_check{
nullptr};
743 if (!null_check_suffix.empty()) {
751 func, std::vector<llvm::Value*>{lhs_lv, rhs_lv});
753 std::vector<unsigned>{0});
755 std::vector<unsigned>{1});
771 phi->addIncoming(ret, val_bb);
llvm::Value * codegenIntArith(const Analyzer::BinOper *, llvm::Value *, llvm::Value *, const CompilationOptions &)
HOST DEVICE int get_size() const
llvm::Value * codegenArith(const Analyzer::BinOper *, const CompilationOptions &)
static std::shared_ptr< Analyzer::Expr > analyzeValue(const int64_t intval)
HOST DEVICE int get_scale() const
const Expr * get_right_operand() const
llvm::Value * codegenMod(llvm::Value *, llvm::Value *, const std::string &null_typename, const std::string &null_check_suffix, const SQLTypeInfo &)
llvm::IRBuilder ir_builder_
llvm::Value * codegenDeciDiv(const Analyzer::BinOper *, const CompilationOptions &)
HOST DEVICE SQLTypes get_type() const
llvm::Type * get_int_type(const int width, llvm::LLVMContext &context)
std::string toString() const override
llvm::Value * codegenFpArith(const Analyzer::BinOper *, llvm::Value *, llvm::Value *)
SQLOps get_optype() const
llvm::LLVMContext & context_
llvm::Function * current_func_
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_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 &)
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
llvm::Value * codegenCastBetweenIntTypes(llvm::Value *operand_lv, const SQLTypeInfo &operand_ti, const SQLTypeInfo &ti, bool upscale=true)
const std::vector< InputTableInfo > & query_infos_
llvm::ConstantFP * llFp(const float v) const
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)
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)
const SQLTypeInfo & get_type_info() const
llvm::Value * codegenUMinus(const Analyzer::UOper *, const CompilationOptions &)
llvm::Value * emitCall(const std::string &fname, const std::vector< llvm::Value * > &args)
ExecutorDeviceType device_type
std::vector< llvm::Value * > codegen(const Analyzer::Expr *, const bool fetch_columns, const CompilationOptions &)
static llvm::ConstantInt * codegenIntConst(const Analyzer::Constant *constant, CgenState *cgen_state)
const shared::ColumnKey & getColumnKey() const
const Expr * get_operand() const
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 *)
llvm::ConstantInt * llInt(const T v) const
llvm::Value * codegenIsNullNumber(llvm::Value *, const SQLTypeInfo &)
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
std::string numeric_type_name(const SQLTypeInfo &ti)
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
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)
std::pair< llvm::ConstantInt *, llvm::ConstantInt * > inlineIntMaxMin(const size_t byte_width, const bool is_signed)
SQLOps get_optype() const
llvm::ConstantFP * inlineFpNull(const SQLTypeInfo &)
Executor * executor() const