1#pragma once
2
3#include "config_core.h"
4#if USE_EMBEDDED_COMPILER
5
6#include <Common/typeid_cast.h>
7#include <DataTypes/DataTypeDate.h>
8#include <DataTypes/DataTypeDateTime.h>
9#include <DataTypes/DataTypeFixedString.h>
10#include <DataTypes/DataTypeInterval.h>
11#include <DataTypes/DataTypeNullable.h>
12#include <DataTypes/DataTypesNumber.h>
13#include <DataTypes/DataTypeUUID.h>
14
15#pragma GCC diagnostic push
16#pragma GCC diagnostic ignored "-Wunused-parameter"
17
18#include <llvm/IR/IRBuilder.h>
19
20#pragma GCC diagnostic pop
21
22
23namespace DB
24{
25
26template <typename... Ts>
27static inline bool typeIsEither(const IDataType & type)
28{
29 return (typeid_cast<const Ts *>(&type) || ...);
30}
31
32static inline bool typeIsSigned(const IDataType & type)
33{
34 return typeIsEither<
35 DataTypeInt8, DataTypeInt16, DataTypeInt32, DataTypeInt64,
36 DataTypeFloat32, DataTypeFloat64, DataTypeInterval
37 >(type);
38}
39
40static inline llvm::Type * toNativeType(llvm::IRBuilderBase & builder, const IDataType & type)
41{
42 if (auto * nullable = typeid_cast<const DataTypeNullable *>(&type))
43 {
44 auto * wrapped = toNativeType(builder, *nullable->getNestedType());
45 return wrapped ? llvm::StructType::get(wrapped, /* is null = */ builder.getInt1Ty()) : nullptr;
46 }
47 /// LLVM doesn't have unsigned types, it has unsigned instructions.
48 if (typeIsEither<DataTypeInt8, DataTypeUInt8>(type))
49 return builder.getInt8Ty();
50 if (typeIsEither<DataTypeInt16, DataTypeUInt16, DataTypeDate>(type))
51 return builder.getInt16Ty();
52 if (typeIsEither<DataTypeInt32, DataTypeUInt32, DataTypeDateTime>(type))
53 return builder.getInt32Ty();
54 if (typeIsEither<DataTypeInt64, DataTypeUInt64, DataTypeInterval>(type))
55 return builder.getInt64Ty();
56 if (typeIsEither<DataTypeUUID>(type))
57 return builder.getInt128Ty();
58 if (typeIsEither<DataTypeFloat32>(type))
59 return builder.getFloatTy();
60 if (typeIsEither<DataTypeFloat64>(type))
61 return builder.getDoubleTy();
62 if (auto * fixed_string = typeid_cast<const DataTypeFixedString *>(&type))
63 return llvm::VectorType::get(builder.getInt8Ty(), fixed_string->getN());
64 return nullptr;
65}
66
67static inline bool canBeNativeType(const IDataType & type)
68{
69 if (auto * nullable = typeid_cast<const DataTypeNullable *>(&type))
70 return canBeNativeType(*nullable->getNestedType());
71
72 return typeIsEither<DataTypeInt8, DataTypeUInt8>(type)
73 || typeIsEither<DataTypeInt16, DataTypeUInt16, DataTypeDate>(type)
74 || typeIsEither<DataTypeInt32, DataTypeUInt32, DataTypeDateTime>(type)
75 || typeIsEither<DataTypeInt64, DataTypeUInt64, DataTypeInterval>(type)
76 || typeIsEither<DataTypeUUID>(type)
77 || typeIsEither<DataTypeFloat32>(type)
78 || typeIsEither<DataTypeFloat64>(type)
79 || typeid_cast<const DataTypeFixedString *>(&type);
80}
81
82static inline llvm::Type * toNativeType(llvm::IRBuilderBase & builder, const DataTypePtr & type)
83{
84 return toNativeType(builder, *type);
85}
86
87static inline llvm::Value * nativeBoolCast(llvm::IRBuilder<> & b, const DataTypePtr & from, llvm::Value * value)
88{
89 if (from->isNullable())
90 {
91 auto * inner = nativeBoolCast(b, removeNullable(from), b.CreateExtractValue(value, {0}));
92 return b.CreateAnd(b.CreateNot(b.CreateExtractValue(value, {1})), inner);
93 }
94 auto * zero = llvm::Constant::getNullValue(value->getType());
95 if (value->getType()->isIntegerTy())
96 return b.CreateICmpNE(value, zero);
97 if (value->getType()->isFloatingPointTy())
98 return b.CreateFCmpONE(value, zero); /// QNaN is false
99 throw Exception("Cannot cast non-number " + from->getName() + " to bool", ErrorCodes::NOT_IMPLEMENTED);
100}
101
102static inline llvm::Value * nativeCast(llvm::IRBuilder<> & b, const DataTypePtr & from, llvm::Value * value, llvm::Type * to)
103{
104 auto * n_from = value->getType();
105 if (n_from == to)
106 return value;
107 if (n_from->isIntegerTy() && to->isFloatingPointTy())
108 return typeIsSigned(*from) ? b.CreateSIToFP(value, to) : b.CreateUIToFP(value, to);
109 if (n_from->isFloatingPointTy() && to->isIntegerTy())
110 return typeIsSigned(*from) ? b.CreateFPToSI(value, to) : b.CreateFPToUI(value, to);
111 if (n_from->isIntegerTy() && to->isIntegerTy())
112 return b.CreateIntCast(value, to, typeIsSigned(*from));
113 if (n_from->isFloatingPointTy() && to->isFloatingPointTy())
114 return b.CreateFPCast(value, to);
115 throw Exception("Cannot cast " + from->getName() + " to requested type", ErrorCodes::NOT_IMPLEMENTED);
116}
117
118static inline llvm::Value * nativeCast(llvm::IRBuilder<> & b, const DataTypePtr & from, llvm::Value * value, const DataTypePtr & to)
119{
120 auto * n_to = toNativeType(b, to);
121 if (value->getType() == n_to)
122 return value;
123 if (from->isNullable() && to->isNullable())
124 {
125 auto * inner = nativeCast(b, removeNullable(from), b.CreateExtractValue(value, {0}), to);
126 return b.CreateInsertValue(inner, b.CreateExtractValue(value, {1}), {1});
127 }
128 if (from->isNullable())
129 return nativeCast(b, removeNullable(from), b.CreateExtractValue(value, {0}), to);
130 if (to->isNullable())
131 {
132 auto * inner = nativeCast(b, from, value, removeNullable(to));
133 return b.CreateInsertValue(llvm::Constant::getNullValue(n_to), inner, {0});
134 }
135 return nativeCast(b, from, value, n_to);
136}
137
138}
139
140#endif
141