#pragma once #include "config_core.h" #if USE_EMBEDDED_COMPILER #include #include #include #include #include #include #include #include #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" #include #pragma GCC diagnostic pop namespace DB { namespace ErrorCodes { extern const int NOT_IMPLEMENTED; } template static inline bool typeIsEither(const IDataType & type) { return (typeid_cast(&type) || ...); } static inline bool typeIsSigned(const IDataType & type) { return typeIsEither< DataTypeInt8, DataTypeInt16, DataTypeInt32, DataTypeInt64, DataTypeFloat32, DataTypeFloat64, DataTypeInterval >(type); } static inline llvm::Type * toNativeType(llvm::IRBuilderBase & builder, const IDataType & type) { if (auto * nullable = typeid_cast(&type)) { auto * wrapped = toNativeType(builder, *nullable->getNestedType()); return wrapped ? llvm::StructType::get(wrapped, /* is null = */ builder.getInt1Ty()) : nullptr; } /// LLVM doesn't have unsigned types, it has unsigned instructions. if (typeIsEither(type)) return builder.getInt8Ty(); if (typeIsEither(type)) return builder.getInt16Ty(); if (typeIsEither(type)) return builder.getInt32Ty(); if (typeIsEither(type)) return builder.getInt64Ty(); if (typeIsEither(type)) return builder.getInt128Ty(); if (typeIsEither(type)) return builder.getFloatTy(); if (typeIsEither(type)) return builder.getDoubleTy(); if (auto * fixed_string = typeid_cast(&type)) return llvm::VectorType::get(builder.getInt8Ty(), fixed_string->getN()); return nullptr; } static inline bool canBeNativeType(const IDataType & type) { if (auto * nullable = typeid_cast(&type)) return canBeNativeType(*nullable->getNestedType()); return typeIsEither(type) || typeIsEither(type) || typeIsEither(type) || typeIsEither(type) || typeIsEither(type) || typeIsEither(type) || typeIsEither(type) || typeid_cast(&type); } static inline llvm::Type * toNativeType(llvm::IRBuilderBase & builder, const DataTypePtr & type) { return toNativeType(builder, *type); } static inline llvm::Value * nativeBoolCast(llvm::IRBuilder<> & b, const DataTypePtr & from, llvm::Value * value) { if (from->isNullable()) { auto * inner = nativeBoolCast(b, removeNullable(from), b.CreateExtractValue(value, {0})); return b.CreateAnd(b.CreateNot(b.CreateExtractValue(value, {1})), inner); } auto * zero = llvm::Constant::getNullValue(value->getType()); if (value->getType()->isIntegerTy()) return b.CreateICmpNE(value, zero); if (value->getType()->isFloatingPointTy()) return b.CreateFCmpONE(value, zero); /// QNaN is false throw Exception("Cannot cast non-number " + from->getName() + " to bool", ErrorCodes::NOT_IMPLEMENTED); } static inline llvm::Value * nativeCast(llvm::IRBuilder<> & b, const DataTypePtr & from, llvm::Value * value, llvm::Type * to) { auto * n_from = value->getType(); if (n_from == to) return value; if (n_from->isIntegerTy() && to->isFloatingPointTy()) return typeIsSigned(*from) ? b.CreateSIToFP(value, to) : b.CreateUIToFP(value, to); if (n_from->isFloatingPointTy() && to->isIntegerTy()) return typeIsSigned(*from) ? b.CreateFPToSI(value, to) : b.CreateFPToUI(value, to); if (n_from->isIntegerTy() && to->isIntegerTy()) return b.CreateIntCast(value, to, typeIsSigned(*from)); if (n_from->isFloatingPointTy() && to->isFloatingPointTy()) return b.CreateFPCast(value, to); throw Exception("Cannot cast " + from->getName() + " to requested type", ErrorCodes::NOT_IMPLEMENTED); } static inline llvm::Value * nativeCast(llvm::IRBuilder<> & b, const DataTypePtr & from, llvm::Value * value, const DataTypePtr & to) { auto * n_to = toNativeType(b, to); if (value->getType() == n_to) return value; if (from->isNullable() && to->isNullable()) { auto * inner = nativeCast(b, removeNullable(from), b.CreateExtractValue(value, {0}), to); return b.CreateInsertValue(inner, b.CreateExtractValue(value, {1}), {1}); } if (from->isNullable()) return nativeCast(b, removeNullable(from), b.CreateExtractValue(value, {0}), to); if (to->isNullable()) { auto * inner = nativeCast(b, from, value, removeNullable(to)); return b.CreateInsertValue(llvm::Constant::getNullValue(n_to), inner, {0}); } return nativeCast(b, from, value, n_to); } } #endif