OmniSciDB  a5dc49c757
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
CastIR.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"
20 
21 llvm::Value* CodeGenerator::codegenCast(const Analyzer::UOper* uoper,
22  const CompilationOptions& co) {
24  CHECK_EQ(uoper->get_optype(), kCAST);
25  const auto& ti = uoper->get_type_info();
26  const auto operand = uoper->get_operand();
27  const auto operand_as_const = dynamic_cast<const Analyzer::Constant*>(operand);
28  // For dictionary encoded constants, the cast holds the dictionary id
29  // information as the compression parameter; handle this case separately.
30  llvm::Value* operand_lv{nullptr};
31  if (operand_as_const) {
32  const auto operand_lvs =
33  codegen(operand_as_const, ti.get_compression(), ti.getStringDictKey(), co);
34  if (operand_lvs.size() == 3) {
35  operand_lv = cgen_state_->emitCall("string_pack", {operand_lvs[1], operand_lvs[2]});
36  } else {
37  operand_lv = operand_lvs.front();
38  }
39  } else {
40  operand_lv = codegen(operand, true, co).front();
41  }
42 
43  // If the operand is a TextEncodingNone struct ({i8*, i64, i8})
44  // unpack it into an int64_t using "string_pack" so that codegenCast
45  // can properly cast it to a TextEncodingDict
46  if (operand_lv->getType()->isPointerTy() &&
47  operand_lv->getType()->getPointerElementType()->isStructTy()) {
48  auto _struct = cgen_state_->ir_builder_.CreateLoad(
49  operand_lv->getType()->getPointerElementType(), operand_lv);
50  auto ptr = cgen_state_->ir_builder_.CreateExtractValue(_struct, {0});
51  auto len = cgen_state_->ir_builder_.CreateTrunc(
52  cgen_state_->ir_builder_.CreateExtractValue(_struct, {1}),
54  executor_->cgen_state_->emitExternalCall(
55  "register_buffer_with_executor_rsm",
56  llvm::Type::getVoidTy(executor_->cgen_state_->context_),
57  {executor_->cgen_state_->llInt(reinterpret_cast<int64_t>(executor_)), ptr});
58  operand_lv = cgen_state_->emitCall("string_pack", {ptr, len});
59  }
60  const auto& operand_ti = operand->get_type_info();
61  return codegenCast(operand_lv, operand_ti, ti, operand_as_const, co);
62 }
63 
64 namespace {
65 
66 bool byte_array_cast(const SQLTypeInfo& operand_ti, const SQLTypeInfo& ti) {
67  return (operand_ti.is_array() && ti.is_array() && ti.get_subtype() == kTINYINT &&
68  operand_ti.get_size() > 0 && operand_ti.get_size() == ti.get_size());
69 }
70 
71 } // namespace
72 
73 llvm::Value* CodeGenerator::codegenCast(llvm::Value* operand_lv,
74  const SQLTypeInfo& operand_ti,
75  const SQLTypeInfo& ti,
76  const bool operand_is_const,
77  const CompilationOptions& co) {
79  if (byte_array_cast(operand_ti, ti)) {
80  auto* byte_array_type = get_int_array_type(8, ti.get_size(), cgen_state_->context_);
81  return cgen_state_->ir_builder_.CreatePointerCast(operand_lv,
82  byte_array_type->getPointerTo());
83  } else if (!operand_ti.is_string() && ti.is_text_encoding_dict()) {
84  return codegenCastNonStringToString(operand_lv, operand_ti, ti, operand_is_const, co);
85  } else if (operand_ti.is_string()) {
86  return codegenCastFromString(operand_lv, operand_ti, ti, operand_is_const, co);
87  } else if (operand_lv->getType()->isIntegerTy()) {
88  CHECK(operand_ti.is_integer() || operand_ti.is_decimal() || operand_ti.is_time() ||
89  operand_ti.is_boolean());
90 
91  if (operand_ti.is_boolean()) {
92  // cast boolean to int8
93  CHECK(operand_lv->getType()->isIntegerTy(1) ||
94  operand_lv->getType()->isIntegerTy(8));
95  if (operand_lv->getType()->isIntegerTy(1)) {
96  operand_lv = cgen_state_->castToTypeIn(operand_lv, 8);
97  }
98  if (ti.is_boolean()) {
99  return operand_lv;
100  }
101  }
102  if (operand_ti.is_integer() && operand_lv->getType()->isIntegerTy(8) &&
103  ti.is_boolean()) {
104  // cast int8 to boolean
105  return codegenCastBetweenIntTypes(operand_lv, operand_ti, ti);
106  }
107  if (operand_ti.get_type() == kTIMESTAMP && ti.get_type() == kDATE) {
108  // Maybe we should instead generate DatetruncExpr directly from RelAlgTranslator
109  // for this pattern. However, DatetruncExpr is supposed to return a timestamp,
110  // whereas this cast returns a date. The underlying type for both is still the same,
111  // but it still doesn't look like a good idea to misuse DatetruncExpr.
112  // Date will have default precision of day, but TIMESTAMP dimension would
113  // matter but while converting date through seconds
115  operand_lv, operand_ti.get_dimension(), !ti.get_notnull());
116  }
117  if (operand_ti.get_type() == kTIMESTAMP && ti.get_type() == kTIME) {
119  operand_lv, operand_ti.get_dimension(), !ti.get_notnull());
120  }
121  if ((operand_ti.get_type() == kTIMESTAMP || operand_ti.get_type() == kDATE) &&
122  ti.get_type() == kTIMESTAMP) {
123  const auto operand_dimen =
124  (operand_ti.is_timestamp()) ? operand_ti.get_dimension() : 0;
125  if (operand_dimen != ti.get_dimension()) {
127  operand_lv, operand_ti, ti, !ti.get_notnull());
128  }
129  }
130  if (ti.is_integer() || ti.is_decimal() || ti.is_time()) {
131  return codegenCastBetweenIntTypes(operand_lv, operand_ti, ti);
132  } else {
133  return codegenCastToFp(operand_lv, operand_ti, ti);
134  }
135  } else {
136  return codegenCastFromFp(operand_lv, operand_ti, ti);
137  }
138  CHECK(false);
139  return nullptr;
140 }
141 
142 llvm::Value* CodeGenerator::codegenCastTimestampToTime(llvm::Value* ts_lv,
143  const int dimen,
144  const bool nullable) {
145  std::vector<llvm::Value*> datetrunc_args{ts_lv};
146  std::string hptodate_fname;
147  if (dimen > 0) {
148  hptodate_fname = "ExtractTimeFromHPTimestamp";
149  datetrunc_args.push_back(
151  } else {
152  hptodate_fname = "ExtractTimeFromLPTimestamp";
153  }
154  if (nullable) {
155  datetrunc_args.push_back(cgen_state_->inlineIntNull(SQLTypeInfo(kBIGINT, false)));
156  hptodate_fname += "Nullable";
157  }
159  hptodate_fname, get_int_type(64, cgen_state_->context_), datetrunc_args);
160 }
161 
162 llvm::Value* CodeGenerator::codegenCastTimestampToDate(llvm::Value* ts_lv,
163  const int dimen,
164  const bool nullable) {
166  CHECK(ts_lv->getType()->isIntegerTy(64));
167  if (dimen > 0) {
168  if (nullable) {
170  "DateTruncateHighPrecisionToDateNullable",
172  {{ts_lv,
175  }
176  return cgen_state_->emitExternalCall(
177  "DateTruncateHighPrecisionToDate",
178  get_int_type(64, cgen_state_->context_),
179  {{ts_lv,
180  cgen_state_->llInt(DateTimeUtils::get_timestamp_precision_scale(dimen))}});
181  }
182  std::unique_ptr<CodeGenerator::NullCheckCodegen> nullcheck_codegen;
183  if (nullable) {
184  nullcheck_codegen =
185  std::make_unique<NullCheckCodegen>(cgen_state_,
186  executor(),
187  ts_lv,
188  SQLTypeInfo(kTIMESTAMP, dimen, 0, !nullable),
189  "cast_timestamp_nullcheck");
190  }
191  auto ret = cgen_state_->emitExternalCall(
192  "datetrunc_day", get_int_type(64, cgen_state_->context_), {ts_lv});
193  if (nullcheck_codegen) {
194  ret = nullcheck_codegen->finalize(ll_int(NULL_BIGINT, cgen_state_->context_), ret);
195  }
196  return ret;
197 }
198 
199 llvm::Value* CodeGenerator::codegenCastBetweenTimestamps(llvm::Value* ts_lv,
200  const SQLTypeInfo& operand_ti,
201  const SQLTypeInfo& target_ti,
202  const bool nullable) {
204  const auto operand_dimen = operand_ti.get_dimension();
205  const auto target_dimen = target_ti.get_dimension();
206  if (operand_dimen == target_dimen) {
207  return ts_lv;
208  }
209  CHECK(ts_lv->getType()->isIntegerTy(64));
210  const auto scale =
211  DateTimeUtils::get_timestamp_precision_scale(abs(operand_dimen - target_dimen));
212  if (operand_dimen < target_dimen) {
213  codegenCastBetweenIntTypesOverflowChecks(ts_lv, operand_ti, target_ti, scale);
214  return nullable
215  ? cgen_state_->emitCall("mul_int64_t_nullable_lhs",
216  {ts_lv,
217  cgen_state_->llInt(static_cast<int64_t>(scale)),
218  cgen_state_->inlineIntNull(operand_ti)})
219  : cgen_state_->ir_builder_.CreateMul(
220  ts_lv, cgen_state_->llInt(static_cast<int64_t>(scale)));
221  }
222  return nullable
223  ? cgen_state_->emitCall("floor_div_nullable_lhs",
224  {ts_lv,
225  cgen_state_->llInt(static_cast<int64_t>(scale)),
226  cgen_state_->inlineIntNull(operand_ti)})
227  : cgen_state_->ir_builder_.CreateSDiv(
228  ts_lv, cgen_state_->llInt(static_cast<int64_t>(scale)));
229 }
230 
231 llvm::Value* CodeGenerator::codegenCastFromString(llvm::Value* operand_lv,
232  const SQLTypeInfo& operand_ti,
233  const SQLTypeInfo& ti,
234  const bool operand_is_const,
235  const CompilationOptions& co) {
237  if (!ti.is_string()) {
238  throw std::runtime_error("Cast from " + operand_ti.get_type_name() + " to " +
239  ti.get_type_name() + " not supported");
240  }
241  if (operand_ti.get_compression() == kENCODING_NONE &&
243  return operand_lv;
244  }
245  if (ti.get_compression() == kENCODING_DICT &&
246  operand_ti.get_compression() == kENCODING_DICT) {
247  if (ti.getStringDictKey() == operand_ti.getStringDictKey()) {
248  return operand_lv;
249  }
250  if (operand_ti.getStringDictKey().dict_id == DictRef::literalsDictId) {
251  // Anything being casted from a literal dictionary is not materialized at this point
252  // Should already have been kicked to CPU if it was originally a GPU query
253 
255  const int64_t source_string_proxy_handle =
256  reinterpret_cast<int64_t>(executor()->getStringDictionaryProxy(
257  operand_ti.getStringDictKey(), executor()->getRowSetMemoryOwner(), true));
258 
259  const int64_t dest_string_proxy_handle =
260  reinterpret_cast<int64_t>(executor()->getStringDictionaryProxy(
261  ti.getStringDictKey(), executor()->getRowSetMemoryOwner(), true));
262 
263  auto source_string_proxy_handle_lv = cgen_state_->llInt(source_string_proxy_handle);
264  auto dest_string_proxy_handle_lv = cgen_state_->llInt(dest_string_proxy_handle);
265 
266  std::vector<llvm::Value*> string_cast_lvs{
267  operand_lv, source_string_proxy_handle_lv, dest_string_proxy_handle_lv};
268  if (ti.is_dict_intersection()) {
270  "intersect_translate_string_id_to_other_dict",
272  string_cast_lvs);
273  } else {
274  return cgen_state_->emitExternalCall("union_translate_string_id_to_other_dict",
276  string_cast_lvs);
277  }
278  }
279 
280  const std::vector<StringOps_Namespace::StringOpInfo> string_op_infos;
281  auto string_dictionary_translation_mgr =
282  std::make_unique<StringDictionaryTranslationMgr>(
283  operand_ti.getStringDictKey(),
284  ti.getStringDictKey(),
286  ti,
287  string_op_infos,
290  executor()->deviceCount(co.device_type),
291  executor(),
292  executor()->getDataMgr(),
293  false /* delay_translation */);
294 
295  return cgen_state_
296  ->moveStringDictionaryTranslationMgr(std::move(string_dictionary_translation_mgr))
297  ->codegen(operand_lv, operand_ti, true /* add_nullcheck */, co);
298  }
299  // dictionary encode non-constant
300  if (operand_ti.get_compression() != kENCODING_DICT && !operand_is_const) {
301  if (g_cluster) {
302  throw std::runtime_error(
303  "Cast from none-encoded string to dictionary-encoded not supported for "
304  "distributed queries");
305  }
306  CHECK_EQ(kENCODING_NONE, operand_ti.get_compression());
308  CHECK(operand_lv->getType()->isStructTy()); // StringView
310  throw QueryMustRunOnCpu();
311  }
313  "string_compress",
315  {operand_lv,
316  cgen_state_->llInt(int64_t(executor()->getStringDictionaryProxy(
317  ti.getStringDictKey(), executor()->getRowSetMemoryOwner(), true)))});
318  }
319  CHECK(operand_lv->getType()->isIntegerTy(32));
320  if (ti.get_compression() == kENCODING_NONE) {
321  if (g_cluster) {
322  throw std::runtime_error(
323  "Cast from dictionary-encoded string to none-encoded not "
324  "currently supported for distributed queries.");
325  }
326  // Removed watchdog check here in exchange for row cardinality based check in
327  // RelAlgExecutor
328  CHECK_EQ(kENCODING_DICT, operand_ti.get_compression());
330  throw QueryMustRunOnCpu();
331  }
332  const int64_t string_dictionary_ptr =
333  operand_ti.getStringDictKey().dict_id == 0
334  ? reinterpret_cast<int64_t>(
335  executor()->getRowSetMemoryOwner()->getLiteralStringDictProxy())
336  : reinterpret_cast<int64_t>(
337  executor()->getStringDictionaryProxy(operand_ti.getStringDictKey(),
338  executor()->getRowSetMemoryOwner(),
339  true));
341  "string_decompress",
343  {operand_lv, cgen_state_->llInt(string_dictionary_ptr)});
344  }
345  CHECK(operand_is_const);
347  return operand_lv;
348 }
349 
350 llvm::Value* CodeGenerator::codegenCastNonStringToString(llvm::Value* operand_lv,
351  const SQLTypeInfo& operand_ti,
352  const SQLTypeInfo& ti,
353  const bool operand_is_const,
354  const CompilationOptions& co) {
356  CHECK(!operand_ti.is_string());
357  if (ti.get_compression() == kENCODING_NONE) {
358  throw std::runtime_error("Cast to none-encoded strings currently unsupported.");
359  }
360  if (g_cluster) {
361  throw std::runtime_error(
362  "Cast to dictionary-encoded string type not supported for "
363  "distributed queries");
364  }
366  throw QueryMustRunOnCpu();
367  }
368  std::string fn_call{"convert_to_string_and_encode_"};
369  const auto operand_type = operand_ti.get_type();
370  std::vector operand_lvs{operand_lv};
371  switch (operand_type) {
372  case kBOOLEAN:
373  fn_call += "bool";
374  break;
375  case kTINYINT:
376  case kSMALLINT:
377  case kINT:
378  case kBIGINT:
379  case kFLOAT:
380  case kDOUBLE:
381  fn_call += to_lower(toString(operand_type));
382  break;
383  case kNUMERIC:
384  case kDECIMAL:
385  fn_call += "decimal";
386  operand_lvs.emplace_back(llvm::ConstantInt::get(
387  get_int_type(32, cgen_state_->context_), operand_ti.get_precision()));
388  operand_lvs.emplace_back(llvm::ConstantInt::get(
389  get_int_type(32, cgen_state_->context_), operand_ti.get_scale()));
390  break;
391  case kTIME:
392  fn_call += "time";
393  break;
394  case kTIMESTAMP:
395  fn_call += "timestamp";
396  operand_lvs.emplace_back(llvm::ConstantInt::get(
397  get_int_type(32, cgen_state_->context_), operand_ti.get_dimension()));
398  break;
399  case kDATE:
400  fn_call += "date";
401  break;
402  default:
403  throw std::runtime_error("Unimplemented type for string cast");
404  }
405  operand_lvs.emplace_back(
406  cgen_state_->llInt(int64_t(executor()->getStringDictionaryProxy(
407  ti.getStringDictKey(), executor()->getRowSetMemoryOwner(), true))));
408 
409  auto ret = cgen_state_->emitExternalCall(
410  fn_call, get_int_type(32, cgen_state_->context_), operand_lvs);
411 
412  std::unique_ptr<CodeGenerator::NullCheckCodegen> nullcheck_codegen;
413  const bool is_nullable = !operand_ti.get_notnull();
414  if (is_nullable) {
415  nullcheck_codegen =
416  std::make_unique<NullCheckCodegen>(cgen_state_,
417  executor(),
418  operand_lvs.front(),
419  operand_ti,
420  "cast_non_string_to_string_nullcheck");
421  CHECK(nullcheck_codegen);
422  ret = nullcheck_codegen->finalize(cgen_state_->inlineNull(ti), ret);
423  }
424  return ret;
425 }
426 
427 llvm::Value* CodeGenerator::codegenCastBetweenIntTypes(llvm::Value* operand_lv,
428  const SQLTypeInfo& operand_ti,
429  const SQLTypeInfo& ti,
430  bool upscale) {
432  if (ti.is_decimal() &&
433  (!operand_ti.is_decimal() || operand_ti.get_scale() <= ti.get_scale())) {
434  if (upscale) {
435  if (operand_ti.get_scale() < ti.get_scale()) { // scale only if needed
436  auto scale = exp_to_scale(ti.get_scale() - operand_ti.get_scale());
437  const auto scale_lv =
438  llvm::ConstantInt::get(get_int_type(64, cgen_state_->context_), scale);
439  operand_lv = cgen_state_->ir_builder_.CreateSExt(
440  operand_lv, get_int_type(64, cgen_state_->context_));
441 
442  codegenCastBetweenIntTypesOverflowChecks(operand_lv, operand_ti, ti, scale);
443 
444  if (operand_ti.get_notnull()) {
445  operand_lv = cgen_state_->ir_builder_.CreateMul(operand_lv, scale_lv);
446  } else {
447  operand_lv = cgen_state_->emitCall(
448  "scale_decimal_up",
449  {operand_lv,
450  scale_lv,
451  cgen_state_->llInt(inline_int_null_val(operand_ti)),
453  }
454  }
455  }
456  } else if (operand_ti.is_decimal()) {
457  // rounded scale down
458  auto scale = (int64_t)exp_to_scale(operand_ti.get_scale() - ti.get_scale());
459  const auto scale_lv =
460  llvm::ConstantInt::get(get_int_type(64, cgen_state_->context_), scale);
461 
462  const auto operand_width =
463  static_cast<llvm::IntegerType*>(operand_lv->getType())->getBitWidth();
464 
465  std::string method_name = "scale_decimal_down_nullable";
466  if (operand_ti.get_notnull()) {
467  method_name = "scale_decimal_down_not_nullable";
468  }
469 
470  CHECK(operand_width == 64);
471  operand_lv = cgen_state_->emitCall(
472  method_name,
473  {operand_lv, scale_lv, cgen_state_->llInt(inline_int_null_val(operand_ti))});
474  }
475  if (ti.is_integer() && operand_ti.is_integer() &&
476  operand_ti.get_logical_size() > ti.get_logical_size()) {
477  codegenCastBetweenIntTypesOverflowChecks(operand_lv, operand_ti, ti, 1);
478  }
479 
480  const auto operand_width =
481  static_cast<llvm::IntegerType*>(operand_lv->getType())->getBitWidth();
482  const auto target_width = get_bit_width(ti);
483  if (target_width == operand_width) {
484  return operand_lv;
485  }
486  if (operand_ti.get_notnull()) {
487  return cgen_state_->ir_builder_.CreateCast(
488  target_width > operand_width ? llvm::Instruction::CastOps::SExt
489  : llvm::Instruction::CastOps::Trunc,
490  operand_lv,
491  get_int_type(target_width, cgen_state_->context_));
492  }
493  return cgen_state_->emitCall("cast_" + numeric_type_name(operand_ti) + "_to_" +
494  numeric_type_name(ti) + "_nullable",
495  {operand_lv,
496  cgen_state_->inlineIntNull(operand_ti),
497  cgen_state_->inlineIntNull(ti)});
498 }
499 
501  llvm::Value* operand_lv,
502  const SQLTypeInfo& operand_ti,
503  const SQLTypeInfo& ti,
504  const int64_t scale) {
506  llvm::Value* chosen_max{nullptr};
507  llvm::Value* chosen_min{nullptr};
508  std::tie(chosen_max, chosen_min) =
510 
512  auto cast_ok = llvm::BasicBlock::Create(
514  auto cast_fail = llvm::BasicBlock::Create(
516  auto operand_max = static_cast<llvm::ConstantInt*>(chosen_max)->getSExtValue() / scale;
517  auto operand_min = static_cast<llvm::ConstantInt*>(chosen_min)->getSExtValue() / scale;
518  const auto ti_llvm_type =
520  llvm::Value* operand_max_lv = llvm::ConstantInt::get(ti_llvm_type, operand_max);
521  llvm::Value* operand_min_lv = llvm::ConstantInt::get(ti_llvm_type, operand_min);
522  const bool is_narrowing = operand_ti.get_logical_size() > ti.get_logical_size();
523  if (is_narrowing) {
524  const auto operand_ti_llvm_type =
526  operand_max_lv =
527  cgen_state_->ir_builder_.CreateSExt(operand_max_lv, operand_ti_llvm_type);
528  operand_min_lv =
529  cgen_state_->ir_builder_.CreateSExt(operand_min_lv, operand_ti_llvm_type);
530  }
531  llvm::Value* over{nullptr};
532  llvm::Value* under{nullptr};
533  if (operand_ti.get_notnull()) {
534  over = cgen_state_->ir_builder_.CreateICmpSGT(operand_lv, operand_max_lv);
535  under = cgen_state_->ir_builder_.CreateICmpSLE(operand_lv, operand_min_lv);
536  } else {
537  const auto type_name =
538  is_narrowing ? numeric_type_name(operand_ti) : numeric_type_name(ti);
539  const auto null_operand_val = cgen_state_->llInt(inline_int_null_val(operand_ti));
540  const auto null_bool_val = cgen_state_->inlineIntNull(SQLTypeInfo(kBOOLEAN, false));
541  over = toBool(cgen_state_->emitCall(
542  "gt_" + type_name + "_nullable_lhs",
543  {operand_lv, operand_max_lv, null_operand_val, null_bool_val}));
544  under = toBool(cgen_state_->emitCall(
545  "le_" + type_name + "_nullable_lhs",
546  {operand_lv, operand_min_lv, null_operand_val, null_bool_val}));
547  }
548  const auto detected = cgen_state_->ir_builder_.CreateOr(over, under, "overflow");
549  cgen_state_->ir_builder_.CreateCondBr(detected, cast_fail, cast_ok);
550 
551  cgen_state_->ir_builder_.SetInsertPoint(cast_fail);
552  cgen_state_->ir_builder_.CreateRet(
553  cgen_state_->llInt(int32_t(heavyai::ErrorCode::OVERFLOW_OR_UNDERFLOW)));
554 
555  cgen_state_->ir_builder_.SetInsertPoint(cast_ok);
556 }
557 
558 llvm::Value* CodeGenerator::codegenCastToFp(llvm::Value* operand_lv,
559  const SQLTypeInfo& operand_ti,
560  const SQLTypeInfo& ti) {
562  if (!ti.is_fp()) {
563  throw std::runtime_error("Cast from " + operand_ti.get_type_name() + " to " +
564  ti.get_type_name() + " not supported");
565  }
566  llvm::Value* result_lv;
567  if (operand_ti.get_notnull()) {
568  auto const fp_type = ti.get_type() == kFLOAT
569  ? llvm::Type::getFloatTy(cgen_state_->context_)
570  : llvm::Type::getDoubleTy(cgen_state_->context_);
571  result_lv = cgen_state_->ir_builder_.CreateSIToFP(operand_lv, fp_type);
572  if (auto const scale = static_cast<unsigned>(operand_ti.get_scale())) {
573  double const divider = shared::power10(scale);
574  result_lv = cgen_state_->ir_builder_.CreateFDiv(
575  result_lv, llvm::ConstantFP::get(result_lv->getType(), divider));
576  }
577  } else {
578  if (auto const scale = static_cast<unsigned>(operand_ti.get_scale())) {
579  double const divider = shared::power10(scale);
580  auto const fp_type = ti.get_type() == kFLOAT
581  ? llvm::Type::getFloatTy(cgen_state_->context_)
582  : llvm::Type::getDoubleTy(cgen_state_->context_);
583  result_lv = cgen_state_->emitCall("cast_" + numeric_type_name(operand_ti) + "_to_" +
584  numeric_type_name(ti) + "_scaled_nullable",
585  {operand_lv,
586  cgen_state_->inlineIntNull(operand_ti),
588  llvm::ConstantFP::get(fp_type, divider)});
589  } else {
590  result_lv = cgen_state_->emitCall("cast_" + numeric_type_name(operand_ti) + "_to_" +
591  numeric_type_name(ti) + "_nullable",
592  {operand_lv,
593  cgen_state_->inlineIntNull(operand_ti),
594  cgen_state_->inlineFpNull(ti)});
595  }
596  }
597  CHECK(result_lv);
598  return result_lv;
599 }
600 
601 llvm::Value* CodeGenerator::codegenCastFromFp(llvm::Value* operand_lv,
602  const SQLTypeInfo& operand_ti,
603  const SQLTypeInfo& ti) {
605  if (!operand_ti.is_fp() || !ti.is_number() || ti.is_decimal()) {
606  throw std::runtime_error("Cast from " + operand_ti.get_type_name() + " to " +
607  ti.get_type_name() + " not supported");
608  }
609  if (operand_ti.get_type() == ti.get_type()) {
610  // Should not have been called when both dimensions are same.
611  return operand_lv;
612  }
613  CHECK(operand_lv->getType()->isFloatTy() || operand_lv->getType()->isDoubleTy());
614  if (operand_ti.get_notnull()) {
615  if (ti.get_type() == kDOUBLE) {
616  return cgen_state_->ir_builder_.CreateFPExt(
617  operand_lv, llvm::Type::getDoubleTy(cgen_state_->context_));
618  } else if (ti.get_type() == kFLOAT) {
619  return cgen_state_->ir_builder_.CreateFPTrunc(
620  operand_lv, llvm::Type::getFloatTy(cgen_state_->context_));
621  } else if (ti.is_integer()) {
622  // Round by adding/subtracting 0.5 before fptosi.
623  auto* fp_type = operand_lv->getType()->isFloatTy()
624  ? llvm::Type::getFloatTy(cgen_state_->context_)
625  : llvm::Type::getDoubleTy(cgen_state_->context_);
626  auto* zero = llvm::ConstantFP::get(fp_type, 0.0);
627  auto* mhalf = llvm::ConstantFP::get(fp_type, -0.5);
628  auto* phalf = llvm::ConstantFP::get(fp_type, 0.5);
629  auto* is_negative = cgen_state_->ir_builder_.CreateFCmpOLT(operand_lv, zero);
630  auto* offset = cgen_state_->ir_builder_.CreateSelect(is_negative, mhalf, phalf);
631  operand_lv = cgen_state_->ir_builder_.CreateFAdd(operand_lv, offset);
632  return cgen_state_->ir_builder_.CreateFPToSI(
633  operand_lv, get_int_type(get_bit_width(ti), cgen_state_->context_));
634  } else {
635  CHECK(false);
636  }
637  } else {
638  const auto from_tname = numeric_type_name(operand_ti);
639  const auto to_tname = numeric_type_name(ti);
640  if (ti.is_fp()) {
641  return cgen_state_->emitCall("cast_" + from_tname + "_to_" + to_tname + "_nullable",
642  {operand_lv,
643  cgen_state_->inlineFpNull(operand_ti),
644  cgen_state_->inlineFpNull(ti)});
645  } else if (ti.is_integer()) {
646  return cgen_state_->emitCall("cast_" + from_tname + "_to_" + to_tname + "_nullable",
647  {operand_lv,
648  cgen_state_->inlineFpNull(operand_ti),
649  cgen_state_->inlineIntNull(ti)});
650  } else {
651  CHECK(false);
652  }
653  }
654  CHECK(false);
655  return nullptr;
656 }
std::string to_lower(const std::string &str)
HOST DEVICE SQLTypes get_subtype() const
Definition: sqltypes.h:392
double power10(unsigned const x)
Definition: misc.h:284
#define CHECK_EQ(x, y)
Definition: Logger.h:301
llvm::Value * castToTypeIn(llvm::Value *val, const size_t bit_width)
Definition: CgenState.cpp:150
llvm::Value * codegenCastFromFp(llvm::Value *operand_lv, const SQLTypeInfo &operand_ti, const SQLTypeInfo &ti)
Definition: CastIR.cpp:601
HOST DEVICE int get_size() const
Definition: sqltypes.h:403
Definition: sqltypes.h:76
bool is_timestamp() const
Definition: sqltypes.h:1046
CgenState * cgen_state_
llvm::Value * codegenCastNonStringToString(llvm::Value *operand_lv, const SQLTypeInfo &operand_ti, const SQLTypeInfo &ti, const bool operand_is_const, const CompilationOptions &co)
Definition: CastIR.cpp:350
#define NULL_BIGINT
bool is_fp() const
Definition: sqltypes.h:573
HOST DEVICE int get_scale() const
Definition: sqltypes.h:396
llvm::ConstantInt * ll_int(const T v, llvm::LLVMContext &context)
llvm::IRBuilder ir_builder_
Definition: CgenState.h:384
llvm::Value * codegenCastToFp(llvm::Value *operand_lv, const SQLTypeInfo &operand_ti, const SQLTypeInfo &ti)
Definition: CastIR.cpp:558
Definition: sqldefs.h:51
bool byte_array_cast(const SQLTypeInfo &operand_ti, const SQLTypeInfo &ti)
Definition: CastIR.cpp:66
HOST DEVICE SQLTypes get_type() const
Definition: sqltypes.h:391
llvm::Type * get_int_type(const int width, llvm::LLVMContext &context)
bool is_number() const
Definition: sqltypes.h:576
bool is_time() const
Definition: sqltypes.h:579
size_t get_bit_width(const SQLTypeInfo &ti)
llvm::LLVMContext & context_
Definition: CgenState.h:382
llvm::Function * current_func_
Definition: CgenState.h:376
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.cpp:395
int get_logical_size() const
Definition: sqltypes.h:421
bool is_integer() const
Definition: sqltypes.h:567
llvm::ConstantInt * inlineIntNull(const SQLTypeInfo &)
Definition: CgenState.cpp:65
bool is_text_encoding_dict() const
Definition: sqltypes.h:617
llvm::Value * codegenCastBetweenIntTypes(llvm::Value *operand_lv, const SQLTypeInfo &operand_ti, const SQLTypeInfo &ti, bool upscale=true)
Definition: CastIR.cpp:427
Executor * executor_
bool is_dict_intersection() const
Definition: sqltypes.h:660
bool needs_error_check_
Definition: CgenState.h:405
bool is_boolean() const
Definition: sqltypes.h:582
llvm::Value * codegenCastTimestampToDate(llvm::Value *ts_lv, const int dimen, const bool nullable)
Definition: CastIR.cpp:162
#define AUTOMATIC_IR_METADATA(CGENSTATE)
std::string toString(const Executor::ExtModuleKinds &kind)
Definition: Execute.h:1703
const SQLTypeInfo & get_type_info() const
Definition: Analyzer.h:79
llvm::Value * emitCall(const std::string &fname, const std::vector< llvm::Value * > &args)
Definition: CgenState.cpp:217
int get_precision() const
Definition: sqltypes.h:394
ExecutorDeviceType device_type
std::vector< llvm::Value * > codegen(const Analyzer::Expr *, const bool fetch_columns, const CompilationOptions &)
Definition: IRCodegen.cpp:30
Definition: sqltypes.h:80
HOST DEVICE EncodingType get_compression() const
Definition: sqltypes.h:399
const Expr * get_operand() const
Definition: Analyzer.h:384
void codegenCastBetweenIntTypesOverflowChecks(llvm::Value *operand_lv, const SQLTypeInfo &operand_ti, const SQLTypeInfo &ti, const int64_t scale)
Definition: CastIR.cpp:500
llvm::StructType * createStringViewStructType()
HOST DEVICE int get_dimension() const
Definition: sqltypes.h:393
std::string get_type_name() const
Definition: sqltypes.h:484
llvm::Value * toBool(llvm::Value *)
Definition: LogicalIR.cpp:344
llvm::Value * codegenCastBetweenTimestamps(llvm::Value *ts_lv, const SQLTypeInfo &operand_dimen, const SQLTypeInfo &target_dimen, const bool nullable)
Definition: CastIR.cpp:199
llvm::ConstantInt * llInt(const T v) const
Definition: CgenState.h:249
#define CHECK(condition)
Definition: Logger.h:291
constexpr int64_t get_timestamp_precision_scale(const int32_t dimen)
Definition: DateTimeUtils.h:51
uint64_t exp_to_scale(const unsigned exp)
int64_t inline_int_null_val(const SQL_TYPE_INFO &ti)
bool g_cluster
llvm::Value * codegenCastTimestampToTime(llvm::Value *ts_lv, const int dimen, const bool nullable)
Definition: CastIR.cpp:142
llvm::Value * codegenCastFromString(llvm::Value *operand_lv, const SQLTypeInfo &operand_ti, const SQLTypeInfo &ti, const bool operand_is_const, const CompilationOptions &co)
Definition: CastIR.cpp:231
const StringDictionaryTranslationMgr * moveStringDictionaryTranslationMgr(std::unique_ptr< const StringDictionaryTranslationMgr > &&str_dict_translation_mgr)
Definition: CgenState.h:199
llvm::Value * codegenCast(const Analyzer::UOper *, const CompilationOptions &)
Definition: CastIR.cpp:21
std::string numeric_type_name(const SQLTypeInfo &ti)
Definition: Execute.h:230
Definition: sqltypes.h:72
bool is_string() const
Definition: sqltypes.h:561
HOST DEVICE bool get_notnull() const
Definition: sqltypes.h:398
llvm::Value * codegen(llvm::Value *str_id_input, const SQLTypeInfo &input_ti, const bool add_nullcheck, const CompilationOptions &co) const
constexpr auto type_name() noexcept
llvm::ArrayType * get_int_array_type(int const width, int count, llvm::LLVMContext &context)
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
bool is_array() const
Definition: sqltypes.h:585
static constexpr int32_t literalsDictId
Definition: DictRef.h:18
const shared::StringDictKey & getStringDictKey() const
Definition: sqltypes.h:1057
llvm::ConstantFP * inlineFpNull(const SQLTypeInfo &)
Definition: CgenState.cpp:104
Executor * executor() const