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 | |
23 | namespace DB |
24 | { |
25 | |
26 | template <typename... Ts> |
27 | static inline bool typeIsEither(const IDataType & type) |
28 | { |
29 | return (typeid_cast<const Ts *>(&type) || ...); |
30 | } |
31 | |
32 | static inline bool typeIsSigned(const IDataType & type) |
33 | { |
34 | return typeIsEither< |
35 | DataTypeInt8, DataTypeInt16, DataTypeInt32, DataTypeInt64, |
36 | DataTypeFloat32, DataTypeFloat64, DataTypeInterval |
37 | >(type); |
38 | } |
39 | |
40 | static 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 | |
67 | static 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 | |
82 | static inline llvm::Type * toNativeType(llvm::IRBuilderBase & builder, const DataTypePtr & type) |
83 | { |
84 | return toNativeType(builder, *type); |
85 | } |
86 | |
87 | static 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 | |
102 | static 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 | |
118 | static 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 | |