Impala
Impalaistheopensource,nativeanalyticdatabaseforApacheHadoop.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
case-expr.cc
Go to the documentation of this file.
1 // Copyright 2012 Cloudera Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "exprs/case-expr.h"
16 
17 #include "codegen/codegen-anyval.h"
18 #include "codegen/llvm-codegen.h"
19 #include "exprs/anyval-util.h"
20 #include "exprs/expr-context.h"
22 #include "runtime/runtime-state.h"
23 
24 #include "gen-cpp/Exprs_types.h"
25 
26 #include "common/names.h"
27 
28 using namespace llvm;
29 
30 namespace impala {
31 
32 struct CaseExprState {
33  // Space to store the values being compared in the interpreted path. This makes it
34  // easier to pass around AnyVal subclasses. Allocated from the runtime state's object
35  // pool in Prepare().
38 };
39 
40 CaseExpr::CaseExpr(const TExprNode& node)
41  : Expr(node),
42  has_case_expr_(node.case_expr.has_case_expr),
43  has_else_expr_(node.case_expr.has_else_expr) {
44 }
45 
47  ExprContext* ctx) {
48  RETURN_IF_ERROR(Expr::Prepare(state, desc, ctx));
49  RegisterFunctionContext(ctx, state);
50  return Status::OK;
51 }
52 
55  RETURN_IF_ERROR(Expr::Open(state, ctx, scope));
57  CaseExprState* case_state =
58  reinterpret_cast<CaseExprState*>(fn_ctx->Allocate(sizeof(CaseExprState)));
59  fn_ctx->SetFunctionState(FunctionContext::THREAD_LOCAL, case_state);
60  if (has_case_expr_) {
61  case_state->case_val = CreateAnyVal(state->obj_pool(), children_[0]->type());
62  case_state->when_val = CreateAnyVal(state->obj_pool(), children_[1]->type());
63  } else {
64  case_state->case_val = CreateAnyVal(state->obj_pool(), TYPE_BOOLEAN);
65  case_state->when_val = CreateAnyVal(state->obj_pool(), children_[0]->type());
66  }
67  return Status::OK;
68 }
69 
72  if (context_index_ != -1) {
74  void* case_state = fn_ctx->GetFunctionState(FunctionContext::THREAD_LOCAL);
75  fn_ctx->Free(reinterpret_cast<uint8_t*>(case_state));
76  }
77  Expr::Close(state, ctx, scope);
78 }
79 
80 string CaseExpr::DebugString() const {
81  stringstream out;
82  out << "CaseExpr(has_case_expr=" << has_case_expr_
83  << " has_else_expr=" << has_else_expr_
84  << " " << Expr::DebugString() << ")";
85  return out.str();
86 }
87 
88 // Sample IR output when there is a case expression and else expression
89 // define i16 @CaseExpr(%"class.impala::ExprContext"* %context,
90 // %"class.impala::TupleRow"* %row) #20 {
91 // eval_case_expr:
92 // %case_val = call i64 @GetSlotRef(%"class.impala::ExprContext"* %context,
93 // %"class.impala::TupleRow"* %row)
94 // %is_null = trunc i64 %case_val to i1
95 // br i1 %is_null, label %return_else_expr, label %eval_first_when_expr
96 //
97 // eval_first_when_expr: ; preds = %eval_case_expr
98 // %when_val = call i64 @Literal(%"class.impala::ExprContext"* %context,
99 // %"class.impala::TupleRow"* %row)
100 // %is_null1 = trunc i64 %when_val to i1
101 // br i1 %is_null1, label %return_else_expr, label %check_when_expr_block
102 //
103 // check_when_expr_block: ; preds = %eval_first_when_expr
104 // %0 = ashr i64 %when_val, 32
105 // %1 = trunc i64 %0 to i32
106 // %2 = ashr i64 %case_val, 32
107 // %3 = trunc i64 %2 to i32
108 // %eq = icmp eq i32 %3, %1
109 // br i1 %eq, label %return_then_expr, label %return_else_expr
110 //
111 // return_then_expr: ; preds = %check_when_expr_block
112 // %then_val = call i16 @Literal12(%"class.impala::ExprContext"* %context,
113 // %"class.impala::TupleRow"* %row)
114 // ret i16 %then_val
115 //
116 // return_else_expr: ; preds = %check_when_expr_block, %eval_first_when_expr, %eval_case_expr
117 // %else_val = call i16 @Literal13(%"class.impala::ExprContext"* %context,
118 // %"class.impala::TupleRow"* %row)
119 // ret i16 %else_val
120 // }
121 //
122 // Sample IR output when there is case expression and no else expression
123 // define i16 @CaseExpr(%"class.impala::ExprContext"* %context,
124 // %"class.impala::TupleRow"* %row) #20 {
125 // eval_case_expr:
126 // %case_val = call i64 @GetSlotRef(%"class.impala::ExprContext"* %context,
127 // %"class.impala::TupleRow"* %row)
128 // %is_null = trunc i64 %case_val to i1
129 // br i1 %is_null, label %return_null, label %eval_first_when_expr
130 //
131 // eval_first_when_expr: ; preds = %eval_case_expr
132 // %when_val = call i64 @Literal(%"class.impala::ExprContext"* %context,
133 // %"class.impala::TupleRow"* %row)
134 // %is_null1 = trunc i64 %when_val to i1
135 // br i1 %is_null1, label %return_null, label %check_when_expr_block
136 //
137 // check_when_expr_block: ; preds = %eval_first_when_expr
138 // %0 = ashr i64 %when_val, 32
139 // %1 = trunc i64 %0 to i32
140 // %2 = ashr i64 %case_val, 32
141 // %3 = trunc i64 %2 to i32
142 // %eq = icmp eq i32 %3, %1
143 // br i1 %eq, label %return_then_expr, label %return_null
144 //
145 // return_then_expr: ; preds = %check_when_expr_block
146 // %then_val = call i16 @Literal12(%"class.impala::ExprContext"* %context,
147 // %"class.impala::TupleRow"* %row)
148 // ret i16 %then_val
149 //
150 // return_null: ; preds = %check_when_expr_block, %eval_first_when_expr, %eval_case_expr
151 // ret i16 1
152 // }
153 //
154 // Sample IR output when there is no case expr and else expression
155 // define i16 @CaseExpr(%"class.impala::ExprContext"* %context,
156 // %"class.impala::TupleRow"* %row) #20 {
157 // eval_first_when_expr:
158 // %when_val = call i16 @Eq_IntVal_IntValWrapper1(
159 // %"class.impala::ExprContext"* %context, %"class.impala::TupleRow"* %row)
160 // %is_null = trunc i16 %when_val to i1
161 // br i1 %is_null, label %return_else_expr, label %check_when_expr_block
162 //
163 // check_when_expr_block: ; preds = %eval_first_when_expr
164 // %0 = ashr i16 %when_val, 8
165 // %1 = trunc i16 %0 to i8
166 // %val = trunc i8 %1 to i1
167 // br i1 %val, label %return_then_expr, label %return_else_expr
168 //
169 // return_then_expr: ; preds = %check_when_expr_block
170 // %then_val = call i16 @Literal14(%"class.impala::ExprContext"* %context,
171 // %"class.impala::TupleRow"* %row)
172 // ret i16 %then_val
173 //
174 // return_else_expr: ; preds = %check_when_expr_block, %eval_first_when_expr
175 // %else_val = call i16 @Literal15(%"class.impala::ExprContext"* %context,
176 // %"class.impala::TupleRow"* %row)
177 // ret i16 %else_val
178 // }
180  if (ir_compute_fn_ != NULL) {
181  *fn = ir_compute_fn_;
182  return Status::OK;
183  }
184 
185  const int num_children = GetNumChildren();
186  Function* child_fns[num_children];
187  for (int i = 0; i < num_children; ++i) {
188  RETURN_IF_ERROR(children()[i]->GetCodegendComputeFn(state, &child_fns[i]));
189  }
190 
191  LlvmCodeGen* codegen;
192  RETURN_IF_ERROR(state->GetCodegen(&codegen));
193  LLVMContext& context = codegen->context();
194  LlvmCodeGen::LlvmBuilder builder(context);
195 
196  Value* args[2];
197  Function* function = CreateIrFunctionPrototype(codegen, "CaseExpr", &args);
198  BasicBlock* eval_case_expr_block = NULL;
199 
200  // This is the block immediately after the when/then exprs. It will either point to a
201  // block which returns the else expr, or returns NULL if no else expr is specified.
202  BasicBlock* default_value_block = BasicBlock::Create(
203  context, has_else_expr() ? "return_else_expr" : "return_null", function);
204 
205  // If there is a case expression, create a block to evaluate it.
206  CodegenAnyVal case_val;
207  BasicBlock* eval_first_when_expr_block = BasicBlock::Create(
208  context, "eval_first_when_expr", function, default_value_block);
209  BasicBlock* current_when_expr_block = eval_first_when_expr_block;
210  if (has_case_expr()) {
211  // Need at least case, when and then expr, and optionally an else expr
212  DCHECK_GE(num_children, (has_else_expr()) ? 4 : 3);
213  // If there is a case expr, create block eval_case_expr to evaluate the
214  // case expr. Place this block before eval_first_when_expr_block
215  eval_case_expr_block = BasicBlock::Create(context, "eval_case_expr",
216  function, eval_first_when_expr_block);
217  builder.SetInsertPoint(eval_case_expr_block);
219  codegen, &builder, children()[0]->type(), child_fns[0], args, "case_val");
220  builder.CreateCondBr(
221  case_val.GetIsNull(), default_value_block, eval_first_when_expr_block);
222  } else {
223  DCHECK_GE(num_children, (has_else_expr()) ? 3 : 2);
224  }
225 
226  const int loop_end = (has_else_expr()) ? num_children - 1 : num_children;
227  const int last_loop_iter = loop_end - 2;
228  // The loop increments by two each time, because each iteration handles one when/then
229  // pair. Both when and then subexpressions are single children. If there is a case expr
230  // start loop at index 1. (case expr is children()[0] and has already be evaluated.
231  for (int i = (has_case_expr()) ? 1 : 0; i < loop_end; i += 2) {
232  BasicBlock* check_when_expr_block = BasicBlock::Create(
233  context, "check_when_expr_block", function, default_value_block);
234  BasicBlock* return_then_expr_block =
235  BasicBlock::Create(context, "return_then_expr", function, default_value_block);
236 
237  // continue_or_exit_block either points to the next eval_next_when_expr block,
238  // or points to the defaut_value_block if there are no more when/then expressions.
239  BasicBlock* continue_or_exit_block = NULL;
240  if (i == last_loop_iter) {
241  continue_or_exit_block = default_value_block;
242  } else {
243  continue_or_exit_block = BasicBlock::Create(
244  context, "eval_next_when_expr", function, default_value_block);
245  }
246 
247  // Get the child value of the when statement. If NULL simply continue to next when
248  // statement
249  builder.SetInsertPoint(current_when_expr_block);
251  codegen, &builder, children()[i]->type(), child_fns[i], args, "when_val");
252  builder.CreateCondBr(
253  when_val.GetIsNull(), continue_or_exit_block, check_when_expr_block);
254 
255  builder.SetInsertPoint(check_when_expr_block);
256  if (has_case_expr()) {
257  // Compare for equality
258  Value* is_equal = case_val.Eq(&when_val);
259  builder.CreateCondBr(is_equal, return_then_expr_block, continue_or_exit_block);
260  } else {
261  builder.CreateCondBr(
262  when_val.GetVal(), return_then_expr_block, continue_or_exit_block);
263  }
264 
265  builder.SetInsertPoint(return_then_expr_block);
266 
267  // Eval and return then value
268  Value* then_val = CodegenAnyVal::CreateCall(
269  codegen, &builder, child_fns[i+1], args, "then_val");
270  builder.CreateRet(then_val);
271 
272  current_when_expr_block = continue_or_exit_block;
273  }
274 
275  builder.SetInsertPoint(default_value_block);
276  if (has_else_expr()) {
277  Value* else_val = CodegenAnyVal::CreateCall(
278  codegen, &builder, child_fns[num_children - 1], args, "else_val");
279  builder.CreateRet(else_val);
280  } else {
281  builder.CreateRet(CodegenAnyVal::GetNullVal(codegen, type()));
282  }
283 
284  *fn = codegen->FinalizeFunction(function);
285  DCHECK(*fn != NULL);
286  ir_compute_fn_ = *fn;
287  return Status::OK;
288 }
289 
290 void CaseExpr::GetChildVal(int child_idx, ExprContext* ctx, TupleRow* row, AnyVal* dst) {
291  switch (children()[child_idx]->type().type) {
292  case TYPE_BOOLEAN:
293  *reinterpret_cast<BooleanVal*>(dst) = children()[child_idx]->GetBooleanVal(ctx, row);
294  break;
295  case TYPE_TINYINT:
296  *reinterpret_cast<TinyIntVal*>(dst) = children()[child_idx]->GetTinyIntVal(ctx, row);
297  break;
298  case TYPE_SMALLINT:
299  *reinterpret_cast<SmallIntVal*>(dst) =
300  children()[child_idx]->GetSmallIntVal(ctx, row);
301  break;
302  case TYPE_INT:
303  *reinterpret_cast<IntVal*>(dst) = children()[child_idx]->GetIntVal(ctx, row);
304  break;
305  case TYPE_BIGINT:
306  *reinterpret_cast<BigIntVal*>(dst) = children()[child_idx]->GetBigIntVal(ctx, row);
307  break;
308  case TYPE_FLOAT:
309  *reinterpret_cast<FloatVal*>(dst) = children()[child_idx]->GetFloatVal(ctx, row);
310  break;
311  case TYPE_DOUBLE:
312  *reinterpret_cast<DoubleVal*>(dst) = children()[child_idx]->GetDoubleVal(ctx, row);
313  break;
314  case TYPE_TIMESTAMP:
315  *reinterpret_cast<TimestampVal*>(dst) =
316  children()[child_idx]->GetTimestampVal(ctx, row);
317  break;
318  case TYPE_STRING:
319  *reinterpret_cast<StringVal*>(dst) = children()[child_idx]->GetStringVal(ctx, row);
320  break;
321  case TYPE_DECIMAL:
322  *reinterpret_cast<DecimalVal*>(dst) = children()[child_idx]->GetDecimalVal(ctx, row);
323  break;
324  default:
325  DCHECK(false) << children()[child_idx]->type();
326  }
327 }
328 
329 bool CaseExpr::AnyValEq(const ColumnType& type, const AnyVal* v1, const AnyVal* v2) {
330  switch (type.type) {
331  case TYPE_BOOLEAN:
332  return AnyValUtil::Equals(type, *reinterpret_cast<const BooleanVal*>(v1),
333  *reinterpret_cast<const BooleanVal*>(v2));
334  case TYPE_TINYINT:
335  return AnyValUtil::Equals(type, *reinterpret_cast<const TinyIntVal*>(v1),
336  *reinterpret_cast<const TinyIntVal*>(v2));
337  case TYPE_SMALLINT:
338  return AnyValUtil::Equals(type, *reinterpret_cast<const SmallIntVal*>(v1),
339  *reinterpret_cast<const SmallIntVal*>(v2));
340  case TYPE_INT:
341  return AnyValUtil::Equals(type, *reinterpret_cast<const IntVal*>(v1),
342  *reinterpret_cast<const IntVal*>(v2));
343  case TYPE_BIGINT:
344  return AnyValUtil::Equals(type, *reinterpret_cast<const BigIntVal*>(v1),
345  *reinterpret_cast<const BigIntVal*>(v2));
346  case TYPE_FLOAT:
347  return AnyValUtil::Equals(type, *reinterpret_cast<const FloatVal*>(v1),
348  *reinterpret_cast<const FloatVal*>(v2));
349  case TYPE_DOUBLE:
350  return AnyValUtil::Equals(type, *reinterpret_cast<const DoubleVal*>(v1),
351  *reinterpret_cast<const DoubleVal*>(v2));
352  case TYPE_TIMESTAMP:
353  return AnyValUtil::Equals(type, *reinterpret_cast<const TimestampVal*>(v1),
354  *reinterpret_cast<const TimestampVal*>(v2));
355  case TYPE_STRING:
356  return AnyValUtil::Equals(type, *reinterpret_cast<const StringVal*>(v1),
357  *reinterpret_cast<const StringVal*>(v2));
358  case TYPE_DECIMAL:
359  return AnyValUtil::Equals(type, *reinterpret_cast<const DecimalVal*>(v1),
360  *reinterpret_cast<const DecimalVal*>(v2));
361  default:
362  DCHECK(false) << type;
363  return false;
364  }
365 }
366 
367 #define CASE_COMPUTE_FN(THEN_TYPE) \
368  THEN_TYPE CaseExpr::Get##THEN_TYPE(ExprContext* ctx, TupleRow* row) { \
369  FunctionContext* fn_ctx = ctx->fn_context(context_index_); \
370  CaseExprState* state = reinterpret_cast<CaseExprState*>( \
371  fn_ctx->GetFunctionState(FunctionContext::THREAD_LOCAL)); \
372  DCHECK(state->case_val != NULL); \
373  DCHECK(state->when_val != NULL); \
374  int num_children = GetNumChildren(); \
375  if (has_case_expr()) { \
376  /* All case and when exprs return the same type */ \
377  /* (we guaranteed that during analysis). */ \
378  GetChildVal(0, ctx, row, state->case_val); \
379  } else { \
380  /* If there's no case expression, compare the when values to "true". */ \
381  *reinterpret_cast<BooleanVal*>(state->case_val) = BooleanVal(true); \
382  } \
383  if (state->case_val->is_null) { \
384  if (has_else_expr()) { \
385  /* Return else value. */ \
386  return children()[num_children - 1]->Get##THEN_TYPE(ctx, row); \
387  } else { \
388  return THEN_TYPE::null(); \
389  } \
390  } \
391  int loop_start = has_case_expr() ? 1 : 0; \
392  int loop_end = (has_else_expr()) ? num_children - 1 : num_children; \
393  for (int i = loop_start; i < loop_end; i += 2) { \
394  GetChildVal(i, ctx, row, state->when_val); \
395  if (state->when_val->is_null) continue; \
396  if (AnyValEq(children()[0]->type(), state->case_val, state->when_val)) { \
397  /* Return then value. */ \
398  return children()[i + 1]->Get##THEN_TYPE(ctx, row); \
399  } \
400  } \
401  if (has_else_expr()) { \
402  /* Return else value. */ \
403  return children()[num_children - 1]->Get##THEN_TYPE(ctx, row); \
404  } \
405  return THEN_TYPE::null(); \
406  }
407 
418 
419 }
bool has_else_expr()
Definition: case-expr.h:60
AnyVal * CreateAnyVal(ObjectPool *pool, const ColumnType &type)
Creates the corresponding AnyVal subclass for type. The object is added to the pool.
Definition: anyval-util.cc:26
llvm::Function * ir_compute_fn_
Cached codegened compute function. Exprs should set this in GetCodegendComputeFn().
Definition: expr.h:299
const std::vector< Expr * > & children() const
Definition: expr.h:148
static CodegenAnyVal CreateCallWrapped(LlvmCodeGen *cg, LlvmCodeGen::LlvmBuilder *builder, const ColumnType &type, llvm::Function *fn, llvm::ArrayRef< llvm::Value * > args, const char *name="", llvm::Value *result_ptr=NULL)
Same as above but wraps the result in a CodegenAnyVal.
llvm::Value * Eq(CodegenAnyVal *other)
Returns the i1 result of this == other. this and other must be non-null.
static Status Open(const std::vector< ExprContext * > &ctxs, RuntimeState *state)
Convenience function for opening multiple expr trees.
const bool has_case_expr_
Definition: case-expr.h:63
static bool Equals(const FunctionContext::TypeDesc *type, const T &x, const T &y)
Templated equality functions. These assume the input values are not NULL.
Definition: anyval-util.h:145
virtual Status Open(RuntimeState *state, ExprContext *context, FunctionContext::FunctionStateScope scope=FunctionContext::FRAGMENT_LOCAL)
Definition: case-expr.cc:53
#define RETURN_IF_ERROR(stmt)
some generally useful macros
Definition: status.h:242
static llvm::Value * CreateCall(LlvmCodeGen *cg, LlvmCodeGen::LlvmBuilder *builder, llvm::Function *fn, llvm::ArrayRef< llvm::Value * > args, const char *name="", llvm::Value *result_ptr=NULL)
'name' optionally specifies the name of the returned value.
bool AnyValEq(const ColumnType &type, const AnyVal *v1, const AnyVal *v2)
Return true iff *v1 == *v2. v1 and v2 should both be of the specified type.
Definition: case-expr.cc:329
#define CASE_COMPUTE_FN(THEN_TYPE)
Definition: case-expr.cc:367
int context_index_
Definition: expr.h:296
This object has a compatible storage format with boost::ptime.
Definition: udf.h:495
virtual Status Prepare(RuntimeState *state, const RowDescriptor &row_desc, ExprContext *context)
Definition: case-expr.cc:46
static void Close(const std::vector< ExprContext * > &ctxs, RuntimeState *state)
Convenience function for closing multiple expr trees.
void GetChildVal(int child_idx, ExprContext *ctx, TupleRow *row, AnyVal *dst)
Definition: case-expr.cc:290
const bool has_else_expr_
Definition: case-expr.h:64
LLVM code generator. This is the top level object to generate jitted code.
Definition: llvm-codegen.h:107
llvm::Function * CreateIrFunctionPrototype(LlvmCodeGen *codegen, const std::string &name, llvm::Value *(*args)[2])
Definition: expr.cc:456
PrimitiveType type
Definition: types.h:60
ObjectPool * obj_pool() const
Definition: runtime-state.h:92
virtual void Close(RuntimeState *state, ExprContext *context, FunctionContext::FunctionStateScope scope=FunctionContext::FRAGMENT_LOCAL)
Subclasses overriding this function should call Expr::Close().
Definition: case-expr.cc:70
bool has_case_expr()
Definition: case-expr.h:59
void * GetFunctionState(FunctionStateScope scope) const
Definition: udf-ir.cc:38
void Free(uint8_t *buffer)
Frees a buffer returned from Allocate() or Reallocate()
Definition: udf.cc:291
This is the superclass of all expr evaluation nodes.
Definition: expr.h:116
void SetFunctionState(FunctionStateScope scope, void *ptr)
Definition: udf.cc:370
const ColumnType & type() const
Definition: expr.h:145
uint8_t * Allocate(int byte_size)
Definition: udf.cc:262
llvm::Value * GetVal(const char *name="val")
static const Status OK
Definition: status.h:87
Status GetCodegen(LlvmCodeGen **codegen, bool initialize=true)
virtual Status GetCodegendComputeFn(RuntimeState *state, llvm::Function **fn)
Definition: case-expr.cc:179
llvm::Value * GetIsNull(const char *name="is_null")
Gets the 'is_null' field of the *Val.
FunctionContext * fn_context(int i)
Definition: expr-context.h:100
llvm::Function * FinalizeFunction(llvm::Function *function)
static Status Prepare(const std::vector< ExprContext * > &ctxs, RuntimeState *state, const RowDescriptor &row_desc, MemTracker *tracker)
static llvm::Value * GetNullVal(LlvmCodeGen *codegen, const ColumnType &type)
std::vector< Expr * > children_
Definition: expr.h:290
llvm::LLVMContext & context()
Definition: llvm-codegen.h:214
virtual std::string DebugString() const
Definition: expr.cc:385
int GetNumChildren() const
Definition: expr.h:143
virtual std::string DebugString() const
Definition: case-expr.cc:80
FunctionContext * RegisterFunctionContext(ExprContext *ctx, RuntimeState *state, int varargs_buffer_size=0)
Definition: expr.cc:80