Sample IR output (when child is a SlotRef): define i16 @IsNotEmptyPredicate(%"class.impala::ScalarExprEvaluator"* %eval, %"class.impala::TupleRow"* %row) #37 { entry: %0 = alloca i16 %1 = alloca i16 %coll_val = call { i64, i8* } @GetSlotRef( %"class.impala::ScalarExprEvaluator"* %eval, %"class.impala::TupleRow"* %row) %2 = extractvalue { i64, i8* } %coll_val, 0 %coll_is_null = trunc i64 %2 to i1 b
| 78 | // ret i16 1 |
| 79 | // } |
| 80 | Status IsNotEmptyPredicate::GetCodegendComputeFnImpl( |
| 81 | LlvmCodeGen* codegen, llvm::Function** fn) { |
| 82 | // Create a method with the expected signature. |
| 83 | llvm::LLVMContext& context = codegen->context(); |
| 84 | llvm::Value* args[2]; |
| 85 | llvm::Function* new_fn = |
| 86 | CreateIrFunctionPrototype("IsNotEmptyPredicate", codegen, &args); |
| 87 | llvm::BasicBlock* entry_block = llvm::BasicBlock::Create(context, "entry", new_fn); |
| 88 | LlvmBuilder builder(entry_block); |
| 89 | |
| 90 | ScalarExpr* child = children_[0]; // The child node, on which to call GetCollectionVal. |
| 91 | llvm::Function* get_collection_val_fn; |
| 92 | RETURN_IF_ERROR(child->GetCodegendComputeFn(codegen, false, &get_collection_val_fn)); |
| 93 | DCHECK(get_collection_val_fn != nullptr); |
| 94 | |
| 95 | // Find type for the CollectionVal struct. |
| 96 | llvm::Type* collection_type = codegen->GetNamedType("struct.impala_udf::CollectionVal"); |
| 97 | DCHECK(collection_type->isStructTy()); |
| 98 | |
| 99 | // Construct the call to the evaluation method, and return the result. |
| 100 | CodegenAnyVal coll_val = CodegenAnyVal::CreateCallWrapped(codegen, &builder, |
| 101 | child->type(), get_collection_val_fn, args, "coll_val"); |
| 102 | |
| 103 | // Find the 'is_null' field of the CollectionVal. |
| 104 | llvm::Value* is_null = coll_val.GetIsNull("coll_is_null"); |
| 105 | |
| 106 | llvm::BasicBlock* check_count = |
| 107 | llvm::BasicBlock::Create(context, "check_count", new_fn); |
| 108 | llvm::BasicBlock* ret_null = llvm::BasicBlock::Create(context, "ret_null", new_fn); |
| 109 | builder.CreateCondBr(is_null, ret_null, check_count); |
| 110 | |
| 111 | // Add code to the block that is executed if is_null was true. |
| 112 | builder.SetInsertPoint(ret_null); |
| 113 | // allocate a BooleanVal, set null in it, and return it. |
| 114 | CodegenAnyVal null_result( |
| 115 | codegen, &builder, ColumnType(TYPE_BOOLEAN), nullptr, "null_result"); |
| 116 | builder.CreateRet( |
| 117 | null_result.GetNullVal(codegen, ColumnType(TYPE_BOOLEAN))); |
| 118 | |
| 119 | // Back to the branch where 'is_null' is false. |
| 120 | builder.SetInsertPoint(check_count); |
| 121 | // Load the value of 'num_tuples'. |
| 122 | llvm::Value* num_tuples = coll_val.GetLen(); |
| 123 | |
| 124 | llvm::Value* has_values = builder.CreateICmpNE(num_tuples, codegen->GetI32Constant(0)); |
| 125 | CodegenAnyVal has_values_result( |
| 126 | codegen, &builder, ColumnType(TYPE_BOOLEAN), nullptr, "has_values_result"); |
| 127 | has_values_result.SetVal(has_values); |
| 128 | builder.CreateRet(has_values_result.GetLoweredValue()); |
| 129 | |
| 130 | *fn = codegen->FinalizeFunction(new_fn); |
| 131 | if (UNLIKELY(*fn == nullptr)) { |
| 132 | return Status(TErrorCode::IR_VERIFY_FAILED, "IsNotEmptyPredicate"); |
| 133 | } |
| 134 | return Status::OK(); |
| 135 | } |
| 136 | |
| 137 | string IsNotEmptyPredicate::DebugString() const { |
nothing calls this directly
no test coverage detected