1#pragma once
2
3#include <Common/config.h>
4#include <Functions/IFunctionImpl.h>
5#include <DataTypes/Native.h>
6
7
8namespace DB
9{
10
11template <bool null_is_false>
12class FunctionIfBase : public IFunction
13{
14#if USE_EMBEDDED_COMPILER
15public:
16 bool isCompilableImpl(const DataTypes & types) const override
17 {
18 /// It's difficult to compare Date and DateTime - cannot use JIT compilation.
19 bool has_date = false;
20 bool has_datetime = false;
21
22 for (const auto & type : types)
23 {
24 auto type_removed_nullable = removeNullable(type);
25 WhichDataType which(type_removed_nullable);
26
27 if (which.isDate())
28 has_date = true;
29 if (which.isDateTime())
30 has_datetime = true;
31
32 if (has_date && has_datetime)
33 return false;
34
35 if (!isCompilableType(type_removed_nullable))
36 return false;
37 }
38 return true;
39 }
40
41 llvm::Value * compileImpl(llvm::IRBuilderBase & builder, const DataTypes & types, ValuePlaceholders values) const override
42 {
43 auto & b = static_cast<llvm::IRBuilder<> &>(builder);
44 auto type = getReturnTypeImpl(types);
45 llvm::Value * null = nullptr;
46 if (!null_is_false && type->isNullable())
47 null = b.CreateInsertValue(llvm::Constant::getNullValue(toNativeType(b, type)), b.getTrue(), {1});
48 auto * head = b.GetInsertBlock();
49 auto * join = llvm::BasicBlock::Create(head->getContext(), "", head->getParent());
50 std::vector<std::pair<llvm::BasicBlock *, llvm::Value *>> returns;
51 for (size_t i = 0; i + 1 < types.size(); i += 2)
52 {
53 auto * then = llvm::BasicBlock::Create(head->getContext(), "", head->getParent());
54 auto * next = llvm::BasicBlock::Create(head->getContext(), "", head->getParent());
55 auto * cond = values[i]();
56 if (!null_is_false && types[i]->isNullable())
57 {
58 auto * nonnull = llvm::BasicBlock::Create(head->getContext(), "", head->getParent());
59 returns.emplace_back(b.GetInsertBlock(), null);
60 b.CreateCondBr(b.CreateExtractValue(cond, {1}), join, nonnull);
61 b.SetInsertPoint(nonnull);
62 b.CreateCondBr(nativeBoolCast(b, removeNullable(types[i]), b.CreateExtractValue(cond, {0})), then, next);
63 }
64 else
65 {
66 b.CreateCondBr(nativeBoolCast(b, types[i], cond), then, next);
67 }
68 b.SetInsertPoint(then);
69 auto * value = nativeCast(b, types[i + 1], values[i + 1](), type);
70 returns.emplace_back(b.GetInsertBlock(), value);
71 b.CreateBr(join);
72 b.SetInsertPoint(next);
73 }
74 auto * value = nativeCast(b, types.back(), values.back()(), type);
75 returns.emplace_back(b.GetInsertBlock(), value);
76 b.CreateBr(join);
77 b.SetInsertPoint(join);
78 auto * phi = b.CreatePHI(toNativeType(b, type), returns.size());
79 for (const auto & r : returns)
80 phi->addIncoming(r.second, r.first);
81 return phi;
82 }
83#endif
84};
85
86}
87