Sample IR output when there is a case expression and else expression define i16 @CaseExpr(%"class.impala::ScalarExprEvaluator"* %context, %"class.impala::TupleRow"* %row) #20 { eval_case_expr: %case_val = call i64 @GetSlotRef(%"class.impala::ScalarExprEvaluator"* %context, %"class.impala::TupleRow"* %row) %is_null = trunc i64 %case_val to i1 br i1 %is_null, label %return_else_expr, label %eval_fir
| 178 | // ret i16 %else_val |
| 179 | // } |
| 180 | Status CaseExpr::GetCodegendComputeFnImpl(LlvmCodeGen* codegen, llvm::Function** fn) { |
| 181 | const int num_children = GetNumChildren(); |
| 182 | vector<llvm::Function*> child_fns(num_children, nullptr); |
| 183 | for (int i = 0; i < num_children; ++i) { |
| 184 | RETURN_IF_ERROR(GetChild(i)->GetCodegendComputeFn(codegen, false, &child_fns[i])); |
| 185 | } |
| 186 | |
| 187 | llvm::LLVMContext& context = codegen->context(); |
| 188 | LlvmBuilder builder(context); |
| 189 | |
| 190 | llvm::Value* args[2]; |
| 191 | llvm::Function* function = CreateIrFunctionPrototype("CaseExpr", codegen, &args); |
| 192 | llvm::BasicBlock* eval_case_expr_block = nullptr; |
| 193 | |
| 194 | // This is the block immediately after the when/then exprs. It will either point to a |
| 195 | // block which returns the else expr, or returns NULL if no else expr is specified. |
| 196 | llvm::BasicBlock* default_value_block = llvm::BasicBlock::Create( |
| 197 | context, has_else_expr() ? "return_else_expr" : "return_null", function); |
| 198 | |
| 199 | // If there is a case expression, create a block to evaluate it. |
| 200 | CodegenAnyVal case_val; |
| 201 | llvm::BasicBlock* eval_first_when_expr_block = llvm::BasicBlock::Create( |
| 202 | context, "eval_first_when_expr", function, default_value_block); |
| 203 | llvm::BasicBlock* current_when_expr_block = eval_first_when_expr_block; |
| 204 | if (has_case_expr()) { |
| 205 | // Need at least case, when and then expr, and optionally an else expr |
| 206 | DCHECK_GE(num_children, has_else_expr() ? 4 : 3); |
| 207 | // If there is a case expr, create block eval_case_expr to evaluate the |
| 208 | // case expr. Place this block before eval_first_when_expr_block |
| 209 | eval_case_expr_block = llvm::BasicBlock::Create( |
| 210 | context, "eval_case_expr", function, eval_first_when_expr_block); |
| 211 | builder.SetInsertPoint(eval_case_expr_block); |
| 212 | case_val = CodegenAnyVal::CreateCallWrapped( |
| 213 | codegen, &builder, children()[0]->type(), child_fns[0], args, "case_val"); |
| 214 | builder.CreateCondBr( |
| 215 | case_val.GetIsNull(), default_value_block, eval_first_when_expr_block); |
| 216 | } else { |
| 217 | DCHECK_GE(num_children, has_else_expr() ? 3 : 2); |
| 218 | } |
| 219 | |
| 220 | const int loop_end = has_else_expr() ? num_children - 1 : num_children; |
| 221 | const int last_loop_iter = loop_end - 2; |
| 222 | // The loop increments by two each time, because each iteration handles one when/then |
| 223 | // pair. Both when and then subexpressions are single children. If there is a case expr |
| 224 | // start loop at index 1. (case expr is GetChild(0) and has already be evaluated. |
| 225 | for (int i = has_case_expr() ? 1 : 0; i < loop_end; i += 2) { |
| 226 | llvm::BasicBlock* check_when_expr_block = llvm::BasicBlock::Create( |
| 227 | context, "check_when_expr_block", function, default_value_block); |
| 228 | llvm::BasicBlock* return_then_expr_block = llvm::BasicBlock::Create( |
| 229 | context, "return_then_expr", function, default_value_block); |
| 230 | |
| 231 | // continue_or_exit_block either points to the next eval_next_when_expr block, |
| 232 | // or points to the defaut_value_block if there are no more when/then expressions. |
| 233 | llvm::BasicBlock* continue_or_exit_block = nullptr; |
| 234 | if (i == last_loop_iter) { |
| 235 | continue_or_exit_block = default_value_block; |
| 236 | } else { |
| 237 | continue_or_exit_block = llvm::BasicBlock::Create( |
nothing calls this directly
no test coverage detected