OmniSciDB  04ee39c94c
DateTimeIR.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2017 MapD Technologies, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "CodeGenerator.h"
18 
19 #include "DateTimeUtils.h"
20 #include "Execute.h"
21 
22 using namespace DateTimeUtils;
23 
24 llvm::Value* CodeGenerator::codegen(const Analyzer::ExtractExpr* extract_expr,
25  const CompilationOptions& co) {
26  auto from_expr = codegen(extract_expr->get_from_expr(), true, co).front();
27  const int32_t extract_field{extract_expr->get_field()};
28  const auto& extract_expr_ti = extract_expr->get_from_expr()->get_type_info();
29  if (extract_field == kEPOCH) {
30  CHECK(extract_expr_ti.get_type() == kTIMESTAMP ||
31  extract_expr_ti.get_type() == kDATE);
32  if (from_expr->getType()->isIntegerTy(32)) {
33  from_expr =
34  cgen_state_->ir_builder_.CreateCast(llvm::Instruction::CastOps::SExt,
35  from_expr,
36  get_int_type(64, cgen_state_->context_));
37  }
38  return from_expr;
39  }
40  CHECK(from_expr->getType()->isIntegerTy(64));
41  if (extract_expr_ti.is_high_precision_timestamp()) {
42  from_expr = codegenExtractHighPrecisionTimestamps(
43  from_expr, extract_expr_ti, extract_expr->get_field());
44  }
45  if (!extract_expr_ti.is_high_precision_timestamp() &&
46  is_subsecond_extract_field(extract_expr->get_field())) {
47  from_expr =
48  extract_expr_ti.get_notnull()
49  ? cgen_state_->ir_builder_.CreateMul(
50  from_expr,
51  cgen_state_->llInt(
53  : cgen_state_->emitCall(
54  "mul_int64_t_nullable_lhs",
55  {from_expr,
56  cgen_state_->llInt(
57  get_extract_timestamp_precision_scale(extract_expr->get_field())),
58  cgen_state_->inlineIntNull(extract_expr_ti)});
59  }
60  std::vector<llvm::Value*> extract_args{
61  cgen_state_->llInt(static_cast<int32_t>(extract_expr->get_field())), from_expr};
62  std::string extract_fname{"ExtractFromTime"};
63  if (!extract_expr_ti.get_notnull()) {
64  extract_args.push_back(cgen_state_->inlineIntNull(extract_expr_ti));
65  extract_fname += "Nullable";
66  }
67  return cgen_state_->emitExternalCall(
68  extract_fname, get_int_type(64, cgen_state_->context_), extract_args);
69 }
70 
71 llvm::Value* CodeGenerator::codegen(const Analyzer::DateaddExpr* dateadd_expr,
72  const CompilationOptions& co) {
73  const auto& dateadd_expr_ti = dateadd_expr->get_type_info();
74  CHECK(dateadd_expr_ti.get_type() == kTIMESTAMP || dateadd_expr_ti.get_type() == kDATE);
75  auto datetime = codegen(dateadd_expr->get_datetime_expr(), true, co).front();
76  CHECK(datetime->getType()->isIntegerTy(64));
77  auto number = codegen(dateadd_expr->get_number_expr(), true, co).front();
78 
79  const auto& datetime_ti = dateadd_expr->get_datetime_expr()->get_type_info();
80  std::vector<llvm::Value*> dateadd_args{
81  cgen_state_->llInt(static_cast<int32_t>(dateadd_expr->get_field())),
82  number,
83  datetime};
84  std::string dateadd_fname{"DateAdd"};
85  if (dateadd_expr_ti.is_high_precision_timestamp()) {
86  dateadd_fname += "HighPrecision";
87  dateadd_args.push_back(cgen_state_->llInt(static_cast<int64_t>(
88  get_timestamp_precision_scale(dateadd_expr_ti.get_dimension()))));
89  }
90  if (!datetime_ti.get_notnull()) {
91  dateadd_args.push_back(cgen_state_->inlineIntNull(datetime_ti));
92  dateadd_fname += "Nullable";
93  }
94  return cgen_state_->emitExternalCall(dateadd_fname,
95  get_int_type(64, cgen_state_->context_),
96  dateadd_args,
97  {llvm::Attribute::NoUnwind,
98  llvm::Attribute::ReadNone,
99  llvm::Attribute::Speculatable});
100 }
101 
102 llvm::Value* CodeGenerator::codegen(const Analyzer::DatediffExpr* datediff_expr,
103  const CompilationOptions& co) {
104  auto start = codegen(datediff_expr->get_start_expr(), true, co).front();
105  CHECK(start->getType()->isIntegerTy(64));
106  auto end = codegen(datediff_expr->get_end_expr(), true, co).front();
107  CHECK(end->getType()->isIntegerTy(32) || end->getType()->isIntegerTy(64));
108  const auto& start_ti = datediff_expr->get_start_expr()->get_type_info();
109  const auto& end_ti = datediff_expr->get_end_expr()->get_type_info();
110  std::vector<llvm::Value*> datediff_args{
111  cgen_state_->llInt(static_cast<int32_t>(datediff_expr->get_field())), start, end};
112  std::string datediff_fname{"DateDiff"};
113  if (start_ti.is_high_precision_timestamp() || end_ti.is_high_precision_timestamp()) {
114  const auto adj_dimen = end_ti.get_dimension() - start_ti.get_dimension();
115  datediff_fname += "HighPrecision";
116  datediff_args.push_back(cgen_state_->llInt(static_cast<int32_t>(adj_dimen)));
117  datediff_args.push_back(cgen_state_->llInt(
118  static_cast<int64_t>(get_timestamp_precision_scale(abs(adj_dimen)))));
119  datediff_args.push_back(
120  cgen_state_->llInt(static_cast<int64_t>(get_timestamp_precision_scale(
121  adj_dimen < 0 ? end_ti.get_dimension() : start_ti.get_dimension()))));
122  datediff_args.push_back(
123  cgen_state_->llInt(static_cast<int64_t>(get_timestamp_precision_scale(
124  adj_dimen > 0 ? end_ti.get_dimension() : start_ti.get_dimension()))));
125  }
126  const auto& ret_ti = datediff_expr->get_type_info();
127  if (!start_ti.get_notnull() || !end_ti.get_notnull()) {
128  datediff_args.push_back(cgen_state_->inlineIntNull(ret_ti));
129  datediff_fname += "Nullable";
130  }
131  return cgen_state_->emitExternalCall(
132  datediff_fname, get_int_type(64, cgen_state_->context_), datediff_args);
133 }
134 
135 llvm::Value* CodeGenerator::codegen(const Analyzer::DatetruncExpr* datetrunc_expr,
136  const CompilationOptions& co) {
137  auto from_expr = codegen(datetrunc_expr->get_from_expr(), true, co).front();
138  const auto& datetrunc_expr_ti = datetrunc_expr->get_from_expr()->get_type_info();
139  CHECK(from_expr->getType()->isIntegerTy(64));
140  if (datetrunc_expr_ti.is_high_precision_timestamp()) {
141  return codegenDateTruncHighPrecisionTimestamps(
142  from_expr, datetrunc_expr_ti, datetrunc_expr->get_field());
143  }
144  std::vector<llvm::Value*> datetrunc_args{
145  cgen_state_->llInt(static_cast<int32_t>(datetrunc_expr->get_field())), from_expr};
146  std::string datetrunc_fname{"DateTruncate"};
147  if (!datetrunc_expr_ti.get_notnull()) {
148  datetrunc_args.push_back(cgen_state_->inlineIntNull(datetrunc_expr_ti));
149  datetrunc_fname += "Nullable";
150  }
151  return cgen_state_->emitExternalCall(
152  datetrunc_fname, get_int_type(64, cgen_state_->context_), datetrunc_args);
153 }
154 
156  llvm::Value* ts_lv,
157  const SQLTypeInfo& ti,
158  const ExtractField& field) {
159  CHECK(ti.is_high_precision_timestamp());
160  CHECK(ts_lv->getType()->isIntegerTy(64));
161  if (is_subsecond_extract_field(field)) {
162  const auto result =
164  if (result.first == kMULTIPLY) {
165  return ti.get_notnull()
166  ? cgen_state_->ir_builder_.CreateMul(
167  ts_lv, cgen_state_->llInt(static_cast<int64_t>(result.second)))
168  : cgen_state_->emitCall(
169  "mul_int64_t_nullable_lhs",
170  {ts_lv,
171  cgen_state_->llInt(static_cast<int64_t>(result.second)),
172  cgen_state_->inlineIntNull(ti)});
173  } else if (result.first == kDIVIDE) {
174  return ti.get_notnull()
175  ? cgen_state_->ir_builder_.CreateSDiv(
176  ts_lv, cgen_state_->llInt(static_cast<int64_t>(result.second)))
177  : cgen_state_->emitCall(
178  "div_int64_t_nullable_lhs",
179  {ts_lv,
180  cgen_state_->llInt(static_cast<int64_t>(result.second)),
181  cgen_state_->inlineIntNull(ti)});
182  } else {
183  return ts_lv;
184  }
185  }
186  return ti.get_notnull()
187  ? cgen_state_->ir_builder_.CreateSDiv(
188  ts_lv,
189  cgen_state_->llInt(static_cast<int64_t>(
191  : cgen_state_->emitCall(
192  "div_int64_t_nullable_lhs",
193  {ts_lv,
194  cgen_state_->llInt(get_timestamp_precision_scale(ti.get_dimension())),
195  cgen_state_->inlineIntNull(ti)});
196 }
197 
199  llvm::Value* ts_lv,
200  const SQLTypeInfo& ti,
201  const DatetruncField& field) {
202  CHECK(ti.is_high_precision_timestamp());
203  CHECK(ts_lv->getType()->isIntegerTy(64));
204  if (is_subsecond_datetrunc_field(field)) {
205  const auto result = get_datetrunc_high_precision_scale(field, ti.get_dimension());
206  if (result != -1) {
207  ts_lv =
208  ti.get_notnull()
209  ? cgen_state_->ir_builder_.CreateSDiv(
210  ts_lv, cgen_state_->llInt(static_cast<int64_t>(result)))
211  : cgen_state_->emitCall("div_int64_t_nullable_lhs",
212  {ts_lv,
213  cgen_state_->llInt(static_cast<int64_t>(result)),
214  cgen_state_->inlineIntNull(ti)});
215  return ti.get_notnull()
216  ? cgen_state_->ir_builder_.CreateMul(
217  ts_lv, cgen_state_->llInt(static_cast<int64_t>(result)))
218  : cgen_state_->emitCall(
219  "mul_int64_t_nullable_lhs",
220  {ts_lv,
221  cgen_state_->llInt(static_cast<int64_t>(result)),
222  cgen_state_->inlineIntNull(ti)});
223  } else {
224  return ts_lv;
225  }
226  }
227  std::string datetrunc_fname = "DateTruncate";
228  const int64_t scale = get_timestamp_precision_scale(ti.get_dimension());
229  ts_lv = ti.get_notnull()
230  ? cgen_state_->ir_builder_.CreateSDiv(
231  ts_lv, cgen_state_->llInt(static_cast<int64_t>(scale)))
232  : cgen_state_->emitCall("div_int64_t_nullable_lhs",
233  {ts_lv,
234  cgen_state_->llInt(static_cast<int64_t>(scale)),
235  cgen_state_->inlineIntNull(ti)});
236  std::vector<llvm::Value*> datetrunc_args{
237  cgen_state_->llInt(static_cast<int32_t>(field)), ts_lv};
238  if (!ti.get_notnull()) {
239  datetrunc_fname += "Nullable";
240  datetrunc_args.push_back(cgen_state_->inlineIntNull(ti));
241  }
242  ts_lv = cgen_state_->emitExternalCall(
243  datetrunc_fname, get_int_type(64, cgen_state_->context_), datetrunc_args);
244  return ti.get_notnull()
245  ? cgen_state_->ir_builder_.CreateMul(
246  ts_lv, cgen_state_->llInt(static_cast<int64_t>(scale)))
247  : cgen_state_->emitCall("mul_int64_t_nullable_lhs",
248  {ts_lv,
249  cgen_state_->llInt(static_cast<int64_t>(scale)),
250  cgen_state_->inlineIntNull(ti)});
251 }
constexpr int64_t get_extract_timestamp_precision_scale(const ExtractField field)
Definition: DateTimeUtils.h:78
HOST DEVICE int get_dimension() const
Definition: sqltypes.h:325
const Expr * get_datetime_expr() const
Definition: Analyzer.h:1131
HOST DEVICE bool get_notnull() const
Definition: sqltypes.h:330
const Expr * get_start_expr() const
Definition: Analyzer.h:1172
DateaddField get_field() const
Definition: Analyzer.h:1129
llvm::Value * codegenExtractHighPrecisionTimestamps(llvm::Value *, const SQLTypeInfo &, const ExtractField &)
Definition: DateTimeIR.cpp:155
const Expr * get_from_expr() const
Definition: Analyzer.h:1089
const std::pair< SQLOps, int64_t > get_extract_high_precision_adjusted_scale(const ExtractField &field, const int32_t dimen)
llvm::Type * get_int_type(const int width, llvm::LLVMContext &context)
DatetruncField get_field() const
Definition: Analyzer.h:1213
const rapidjson::Value & field(const rapidjson::Value &obj, const char field[]) noexcept
Definition: JsonAccessors.h:31
DatetruncField
Definition: DateTruncate.h:42
constexpr bool is_subsecond_datetrunc_field(const DatetruncField field)
const Expr * get_from_expr() const
Definition: Analyzer.h:1214
DatetruncField get_field() const
Definition: Analyzer.h:1171
std::vector< llvm::Value * > codegen(const Analyzer::Expr *, const bool fetch_columns, const CompilationOptions &)
Definition: IRCodegen.cpp:25
Definition: sqltypes.h:55
ExtractField
const SQLTypeInfo & get_type_info() const
Definition: Analyzer.h:77
#define CHECK(condition)
Definition: Logger.h:187
constexpr int64_t get_timestamp_precision_scale(const int32_t dimen)
Definition: DateTimeUtils.h:48
llvm::Value * codegenDateTruncHighPrecisionTimestamps(llvm::Value *, const SQLTypeInfo &, const DatetruncField &)
Definition: DateTimeIR.cpp:198
ExtractField get_field() const
Definition: Analyzer.h:1088
const Expr * get_end_expr() const
Definition: Analyzer.h:1173
const Expr * get_number_expr() const
Definition: Analyzer.h:1130
constexpr bool is_subsecond_extract_field(const ExtractField &field)
Definition: DateTimeUtils.h:92
const int64_t get_datetrunc_high_precision_scale(const DatetruncField &field, const int32_t dimen)