mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-09-22 17:50:47 +00:00
Implement jit for most arithmetic functions, remove the test function
This commit is contained in:
parent
7529aa55a4
commit
059bbcacca
@ -4,6 +4,7 @@
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
|
||||
#include <Common/typeid_cast.h>
|
||||
#include <DataTypes/DataTypeDate.h>
|
||||
#include <DataTypes/DataTypeDateTime.h>
|
||||
#include <DataTypes/DataTypeFixedString.h>
|
||||
@ -55,6 +56,21 @@ static inline llvm::Type * toNativeType(llvm::IRBuilderBase & builder, const Dat
|
||||
return toNativeType(builder, *type);
|
||||
}
|
||||
|
||||
static inline llvm::Value * castNativeNumber(llvm::IRBuilder<> & builder, llvm::Value * value, llvm::Type * type, bool is_signed)
|
||||
{
|
||||
if (value->getType() == type)
|
||||
return value;
|
||||
if (value->getType()->isIntegerTy())
|
||||
{
|
||||
if (type->isIntegerTy())
|
||||
return builder.CreateIntCast(value, type, is_signed);
|
||||
return is_signed ? builder.CreateSIToFP(value, type) : builder.CreateUIToFP(value, type);
|
||||
}
|
||||
if (type->isFloatingPointTy())
|
||||
return builder.CreateFPCast(value, type);
|
||||
return is_signed ? builder.CreateFPToSI(value, type) : builder.CreateFPToUI(value, type);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -104,10 +104,7 @@ if (ENABLE_TESTS)
|
||||
endif ()
|
||||
|
||||
if (USE_EMBEDDED_COMPILER)
|
||||
#llvm_map_components_to_libraries(REQUIRED_LLVM_LIBRARIES all)
|
||||
#target_link_libraries(clickhouse_functions PRIVATE ${REQUIRED_LLVM_LIBRARIES})
|
||||
target_include_directories (clickhouse_functions BEFORE PUBLIC ${LLVM_INCLUDE_DIRS})
|
||||
# LLVM 5.0 has a bunch of unused parameters in its header files.
|
||||
# TODO: global-disable this warning
|
||||
set_source_files_properties(FunctionsLLVMTest.cpp PROPERTIES COMPILE_FLAGS "-Wno-unused-parameter -g")
|
||||
# LLVM has a bunch of unused parameters in its header files.
|
||||
target_compile_options (clickhouse_functions PRIVATE "-Wno-unused-parameter")
|
||||
endif ()
|
||||
|
@ -5,12 +5,16 @@
|
||||
#include <Columns/ColumnNullable.h>
|
||||
#include <DataTypes/DataTypeNullable.h>
|
||||
#include <IO/WriteHelpers.h>
|
||||
#include "FunctionsArithmetic.h"
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int ILLEGAL_COLUMN;
|
||||
}
|
||||
|
||||
const ColumnConst * checkAndGetColumnConstStringOrFixedString(const IColumn * column)
|
||||
{
|
||||
if (!column->isColumnConst())
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <DataTypes/DataTypeDate.h>
|
||||
#include <DataTypes/DataTypeDateTime.h>
|
||||
#include <DataTypes/DataTypeInterval.h>
|
||||
#include <DataTypes/Native.h>
|
||||
#include <Columns/ColumnVector.h>
|
||||
#include <Columns/ColumnConst.h>
|
||||
#include <Functions/IFunction.h>
|
||||
@ -19,6 +20,10 @@
|
||||
#include <common/intExp.h>
|
||||
#include <boost/math/common_factor.hpp>
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
#include <llvm/IR/IRBuilder.h>
|
||||
#endif
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
@ -106,6 +111,15 @@ struct PlusImpl
|
||||
/// Next everywhere, static_cast - so that there is no wrong result in expressions of the form Int64 c = UInt32(a) * Int32(-1).
|
||||
return static_cast<Result>(a) + b;
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
static constexpr bool compilable = true;
|
||||
|
||||
static inline llvm::Value * compile(llvm::IRBuilder<> & b, llvm::Value * left, llvm::Value * right, bool)
|
||||
{
|
||||
return left->getType()->isIntegerTy() ? b.CreateAdd(left, right) : b.CreateFAdd(left, right);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@ -119,6 +133,15 @@ struct MultiplyImpl
|
||||
{
|
||||
return static_cast<Result>(a) * b;
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
static constexpr bool compilable = true;
|
||||
|
||||
static inline llvm::Value * compile(llvm::IRBuilder<> & b, llvm::Value * left, llvm::Value * right, bool)
|
||||
{
|
||||
return left->getType()->isIntegerTy() ? b.CreateMul(left, right) : b.CreateFMul(left, right);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename A, typename B>
|
||||
@ -131,6 +154,15 @@ struct MinusImpl
|
||||
{
|
||||
return static_cast<Result>(a) - b;
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
static constexpr bool compilable = true;
|
||||
|
||||
static inline llvm::Value * compile(llvm::IRBuilder<> & b, llvm::Value * left, llvm::Value * right, bool)
|
||||
{
|
||||
return left->getType()->isIntegerTy() ? b.CreateSub(left, right) : b.CreateFSub(left, right);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename A, typename B>
|
||||
@ -143,6 +175,17 @@ struct DivideFloatingImpl
|
||||
{
|
||||
return static_cast<Result>(a) / b;
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
static constexpr bool compilable = true;
|
||||
|
||||
static inline llvm::Value * compile(llvm::IRBuilder<> & b, llvm::Value * left, llvm::Value * right, bool)
|
||||
{
|
||||
if (left->getType()->isIntegerTy())
|
||||
throw Exception("DivideFloatingImpl expected a floating-point type", ErrorCodes::LOGICAL_ERROR);
|
||||
return b.CreateFDiv(left, right);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@ -189,6 +232,10 @@ struct DivideIntegralImpl
|
||||
throwIfDivisionLeadsToFPE(a, b);
|
||||
return a / b;
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
static constexpr bool compilable = false; /// don't know how to throw from LLVM IR
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename A, typename B>
|
||||
@ -201,6 +248,10 @@ struct DivideIntegralOrZeroImpl
|
||||
{
|
||||
return unlikely(divisionLeadsToFPE(a, b)) ? 0 : a / b;
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
static constexpr bool compilable = false; /// TODO implement the checks
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename A, typename B>
|
||||
@ -212,9 +263,12 @@ struct ModuloImpl
|
||||
static inline Result apply(A a, B b)
|
||||
{
|
||||
throwIfDivisionLeadsToFPE(typename NumberTraits::ToInteger<A>::Type(a), typename NumberTraits::ToInteger<B>::Type(b));
|
||||
return typename NumberTraits::ToInteger<A>::Type(a)
|
||||
% typename NumberTraits::ToInteger<B>::Type(b);
|
||||
return typename NumberTraits::ToInteger<A>::Type(a) % typename NumberTraits::ToInteger<B>::Type(b);
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
static constexpr bool compilable = false; /// don't know how to throw from LLVM IR
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename A, typename B>
|
||||
@ -225,9 +279,19 @@ struct BitAndImpl
|
||||
template <typename Result = ResultType>
|
||||
static inline Result apply(A a, B b)
|
||||
{
|
||||
return static_cast<Result>(a)
|
||||
& static_cast<Result>(b);
|
||||
return static_cast<Result>(a) & static_cast<Result>(b);
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
static constexpr bool compilable = true;
|
||||
|
||||
static inline llvm::Value * compile(llvm::IRBuilder<> & b, llvm::Value * left, llvm::Value * right, bool)
|
||||
{
|
||||
if (!left->getType()->isIntegerTy())
|
||||
throw Exception("BitAndImpl expected an integral type", ErrorCodes::LOGICAL_ERROR);
|
||||
return b.CreateAnd(left, right);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename A, typename B>
|
||||
@ -238,9 +302,19 @@ struct BitOrImpl
|
||||
template <typename Result = ResultType>
|
||||
static inline Result apply(A a, B b)
|
||||
{
|
||||
return static_cast<Result>(a)
|
||||
| static_cast<Result>(b);
|
||||
return static_cast<Result>(a) | static_cast<Result>(b);
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
static constexpr bool compilable = true;
|
||||
|
||||
static inline llvm::Value * compile(llvm::IRBuilder<> & b, llvm::Value * left, llvm::Value * right, bool)
|
||||
{
|
||||
if (!left->getType()->isIntegerTy())
|
||||
throw Exception("BitOrImpl expected an integral type", ErrorCodes::LOGICAL_ERROR);
|
||||
return b.CreateOr(left, right);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename A, typename B>
|
||||
@ -251,9 +325,19 @@ struct BitXorImpl
|
||||
template <typename Result = ResultType>
|
||||
static inline Result apply(A a, B b)
|
||||
{
|
||||
return static_cast<Result>(a)
|
||||
^ static_cast<Result>(b);
|
||||
return static_cast<Result>(a) ^ static_cast<Result>(b);
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
static constexpr bool compilable = true;
|
||||
|
||||
static inline llvm::Value * compile(llvm::IRBuilder<> & b, llvm::Value * left, llvm::Value * right, bool)
|
||||
{
|
||||
if (!left->getType()->isIntegerTy())
|
||||
throw Exception("BitXorImpl expected an integral type", ErrorCodes::LOGICAL_ERROR);
|
||||
return b.CreateXor(left, right);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename A, typename B>
|
||||
@ -264,9 +348,19 @@ struct BitShiftLeftImpl
|
||||
template <typename Result = ResultType>
|
||||
static inline Result apply(A a, B b)
|
||||
{
|
||||
return static_cast<Result>(a)
|
||||
<< static_cast<Result>(b);
|
||||
return static_cast<Result>(a) << static_cast<Result>(b);
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
static constexpr bool compilable = true;
|
||||
|
||||
static inline llvm::Value * compile(llvm::IRBuilder<> & b, llvm::Value * left, llvm::Value * right, bool)
|
||||
{
|
||||
if (!left->getType()->isIntegerTy())
|
||||
throw Exception("BitShiftLeftImpl expected an integral type", ErrorCodes::LOGICAL_ERROR);
|
||||
return b.CreateShl(left, right);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename A, typename B>
|
||||
@ -277,9 +371,19 @@ struct BitShiftRightImpl
|
||||
template <typename Result = ResultType>
|
||||
static inline Result apply(A a, B b)
|
||||
{
|
||||
return static_cast<Result>(a)
|
||||
>> static_cast<Result>(b);
|
||||
return static_cast<Result>(a) >> static_cast<Result>(b);
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
static constexpr bool compilable = true;
|
||||
|
||||
static inline llvm::Value * compile(llvm::IRBuilder<> & b, llvm::Value * left, llvm::Value * right, bool is_signed)
|
||||
{
|
||||
if (!left->getType()->isIntegerTy())
|
||||
throw Exception("BitShiftRightImpl expected an integral type", ErrorCodes::LOGICAL_ERROR);
|
||||
return is_signed ? b.CreateAShr(left, right) : b.CreateLShr(left, right);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename A, typename B>
|
||||
@ -293,6 +397,19 @@ struct BitRotateLeftImpl
|
||||
return (static_cast<Result>(a) << static_cast<Result>(b))
|
||||
| (static_cast<Result>(a) >> ((sizeof(Result) * 8) - static_cast<Result>(b)));
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
static constexpr bool compilable = true;
|
||||
|
||||
static inline llvm::Value * compile(llvm::IRBuilder<> & b, llvm::Value * left, llvm::Value * right, bool)
|
||||
{
|
||||
if (!left->getType()->isIntegerTy())
|
||||
throw Exception("BitRotateLeftImpl expected an integral type", ErrorCodes::LOGICAL_ERROR);
|
||||
auto * size = llvm::ConstantInt::get(left->getType(), left->getType()->getPrimitiveSizeInBits());
|
||||
/// XXX how is this supposed to behave in signed mode?
|
||||
return b.CreateOr(b.CreateShl(left, right), b.CreateLShr(left, b.CreateSub(size, right)));
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename A, typename B>
|
||||
@ -306,24 +423,35 @@ struct BitRotateRightImpl
|
||||
return (static_cast<Result>(a) >> static_cast<Result>(b))
|
||||
| (static_cast<Result>(a) << ((sizeof(Result) * 8) - static_cast<Result>(b)));
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
static constexpr bool compilable = true;
|
||||
|
||||
static inline llvm::Value * compile(llvm::IRBuilder<> & b, llvm::Value * left, llvm::Value * right, bool)
|
||||
{
|
||||
if (!left->getType()->isIntegerTy())
|
||||
throw Exception("BitRotateRightImpl expected an integral type", ErrorCodes::LOGICAL_ERROR);
|
||||
auto * size = llvm::ConstantInt::get(left->getType(), left->getType()->getPrimitiveSizeInBits());
|
||||
return b.CreateOr(b.CreateLShr(left, right), b.CreateShl(left, b.CreateSub(size, right)));
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_integral_v<T>, T> toInteger(T x) { return x; }
|
||||
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_floating_point_v<T>, Int64> toInteger(T x) { return Int64(x); }
|
||||
|
||||
template <typename A, typename B>
|
||||
struct BitTestImpl
|
||||
{
|
||||
using ResultType = UInt8;
|
||||
|
||||
template <typename Result = ResultType>
|
||||
static inline Result apply(A a, B b) { return (toInteger(a) >> toInteger(b)) & 1; };
|
||||
};
|
||||
static inline Result apply(A a, B b)
|
||||
{
|
||||
return (typename NumberTraits::ToInteger<A>::Type(a) >> typename NumberTraits::ToInteger<B>::Type(b)) & 1;
|
||||
};
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
static constexpr bool compilable = false; /// TODO
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename A, typename B>
|
||||
struct LeastBaseImpl
|
||||
@ -336,6 +464,18 @@ struct LeastBaseImpl
|
||||
/** gcc 4.9.2 successfully vectorizes a loop from this function. */
|
||||
return static_cast<Result>(a) < static_cast<Result>(b) ? static_cast<Result>(a) : static_cast<Result>(b);
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
static constexpr bool compilable = true;
|
||||
|
||||
static inline llvm::Value * compile(llvm::IRBuilder<> & b, llvm::Value * left, llvm::Value * right, bool is_signed)
|
||||
{
|
||||
if (!left->getType()->isIntegerTy())
|
||||
/// XXX minnum is basically fmin(), it may or may not match whatever apply() does
|
||||
return b.CreateMinNum(left, right);
|
||||
return b.CreateSelect(is_signed ? b.CreateICmpSLT(left, right) : b.CreateICmpULT(left, right), left, right);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename A, typename B>
|
||||
@ -349,6 +489,10 @@ struct LeastSpecialImpl
|
||||
static_assert(std::is_same_v<Result, ResultType>, "ResultType != Result");
|
||||
return accurate::lessOp(a, b) ? static_cast<Result>(a) : static_cast<Result>(b);
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
static constexpr bool compilable = false; /// ???
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename A, typename B>
|
||||
@ -365,6 +509,18 @@ struct GreatestBaseImpl
|
||||
{
|
||||
return static_cast<Result>(a) > static_cast<Result>(b) ? static_cast<Result>(a) : static_cast<Result>(b);
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
static constexpr bool compilable = true;
|
||||
|
||||
static inline llvm::Value * compile(llvm::IRBuilder<> & b, llvm::Value * left, llvm::Value * right, bool is_signed)
|
||||
{
|
||||
if (!left->getType()->isIntegerTy())
|
||||
/// XXX maxnum is basically fmax(), it may or may not match whatever apply() does
|
||||
return b.CreateMaxNum(left, right);
|
||||
return b.CreateSelect(is_signed ? b.CreateICmpSGT(left, right) : b.CreateICmpUGT(left, right), left, right);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename A, typename B>
|
||||
@ -378,6 +534,10 @@ struct GreatestSpecialImpl
|
||||
static_assert(std::is_same_v<Result, ResultType>, "ResultType != Result");
|
||||
return accurate::greaterOp(a, b) ? static_cast<Result>(a) : static_cast<Result>(b);
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
static constexpr bool compilable = false; /// ???
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename A, typename B>
|
||||
@ -393,6 +553,15 @@ struct NegateImpl
|
||||
{
|
||||
return -static_cast<ResultType>(a);
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
static constexpr bool compilable = true;
|
||||
|
||||
static inline llvm::Value * compile(llvm::IRBuilder<> & b, llvm::Value * arg, bool)
|
||||
{
|
||||
return arg->getType()->isIntegerTy() ? b.CreateNeg(arg) : b.CreateFNeg(arg);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename A>
|
||||
@ -404,6 +573,17 @@ struct BitNotImpl
|
||||
{
|
||||
return ~static_cast<ResultType>(a);
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
static constexpr bool compilable = true;
|
||||
|
||||
static inline llvm::Value * compile(llvm::IRBuilder<> & b, llvm::Value * arg, bool)
|
||||
{
|
||||
if (!arg->getType()->isIntegerTy())
|
||||
throw Exception("BitNotImpl expected an integral type", ErrorCodes::LOGICAL_ERROR);
|
||||
return b.CreateNot(arg);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename A>
|
||||
@ -420,6 +600,10 @@ struct AbsImpl
|
||||
else if constexpr (std::is_floating_point_v<A>)
|
||||
return static_cast<ResultType>(std::abs(a));
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
static constexpr bool compilable = false; /// special type handling, some other time
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename A, typename B>
|
||||
@ -436,6 +620,10 @@ struct GCDImpl
|
||||
typename NumberTraits::ToInteger<Result>::Type(a),
|
||||
typename NumberTraits::ToInteger<Result>::Type(b));
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
static constexpr bool compilable = false; /// exceptions (and a non-trivial algorithm)
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename A, typename B>
|
||||
@ -452,6 +640,10 @@ struct LCMImpl
|
||||
typename NumberTraits::ToInteger<Result>::Type(a),
|
||||
typename NumberTraits::ToInteger<Result>::Type(b));
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
static constexpr bool compilable = false; /// exceptions (and a non-trivial algorithm)
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename A>
|
||||
@ -463,6 +655,10 @@ struct IntExp2Impl
|
||||
{
|
||||
return intExp2(a);
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
static constexpr bool compilable = false; /// library function
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename A>
|
||||
@ -474,6 +670,10 @@ struct IntExp10Impl
|
||||
{
|
||||
return intExp10(a);
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
static constexpr bool compilable = false; /// library function
|
||||
#endif
|
||||
};
|
||||
|
||||
/// Used to indicate undefined operation
|
||||
@ -745,6 +945,43 @@ public:
|
||||
if (!valid)
|
||||
throw Exception(getName() + "'s arguments do not match the expected data types", ErrorCodes::LOGICAL_ERROR);
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
bool isCompilableImpl(const DataTypes & arguments) const override
|
||||
{
|
||||
return castBothTypes(arguments[0].get(), arguments[1].get(), [&](const auto & left, const auto & right)
|
||||
{
|
||||
using LeftDataType = std::decay_t<decltype(left)>;
|
||||
using RightDataType = std::decay_t<decltype(right)>;
|
||||
using ResultDataType = typename BinaryOperationTraits<Op, LeftDataType, RightDataType>::ResultDataType;
|
||||
using OpSpec = Op<typename LeftDataType::FieldType, typename RightDataType::FieldType>;
|
||||
return !std::is_same_v<ResultDataType, InvalidType> && OpSpec::compilable;
|
||||
});
|
||||
}
|
||||
|
||||
llvm::Value * compileImpl(llvm::IRBuilderBase & builder, const DataTypes & types, ValuePlaceholders values) const override
|
||||
{
|
||||
llvm::Value * result = nullptr;
|
||||
castBothTypes(types[0].get(), types[1].get(), [&](const auto & left, const auto & right)
|
||||
{
|
||||
using LeftDataType = std::decay_t<decltype(left)>;
|
||||
using RightDataType = std::decay_t<decltype(right)>;
|
||||
using ResultDataType = typename BinaryOperationTraits<Op, LeftDataType, RightDataType>::ResultDataType;
|
||||
using OpSpec = Op<typename LeftDataType::FieldType, typename RightDataType::FieldType>;
|
||||
if constexpr (!std::is_same_v<ResultDataType, InvalidType> && OpSpec::compilable)
|
||||
{
|
||||
auto & b = static_cast<llvm::IRBuilder<> &>(builder);
|
||||
auto * type = toNativeType(b, ResultDataType{});
|
||||
auto * lval = castNativeNumber(b, values[0](), type, std::is_signed_v<typename LeftDataType::FieldType>);
|
||||
auto * rval = castNativeNumber(b, values[1](), type, std::is_signed_v<typename RightDataType::FieldType>);
|
||||
result = OpSpec::compile(b, lval, rval, std::is_signed_v<typename ResultDataType::FieldType>);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@ -821,6 +1058,35 @@ public:
|
||||
throw Exception(getName() + "'s argument does not match the expected data type", ErrorCodes::LOGICAL_ERROR);
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
bool isCompilableImpl(const DataTypes & arguments) const override
|
||||
{
|
||||
return castType(arguments[0].get(), [&](const auto & type)
|
||||
{
|
||||
return Op<typename std::decay_t<decltype(type)>::FieldType>::compilable;
|
||||
});
|
||||
}
|
||||
|
||||
llvm::Value * compileImpl(llvm::IRBuilderBase & builder, const DataTypes & types, ValuePlaceholders values) const override
|
||||
{
|
||||
llvm::Value * result = nullptr;
|
||||
castType(types[0].get(), [&](const auto & type)
|
||||
{
|
||||
using T0 = typename std::decay_t<decltype(type)>::FieldType;
|
||||
using T1 = typename Op<T0>::ResultType;
|
||||
if constexpr (Op<T1>::compilable)
|
||||
{
|
||||
auto & b = static_cast<llvm::IRBuilder<> &>(builder);
|
||||
auto * v = castNativeNumber(b, values[0](), toNativeType(b, DataTypeNumber<T1>{}), std::is_signed_v<T0>);
|
||||
result = Op<T0>::compile(b, v, std::is_signed_v<T1>);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool hasInformationAboutMonotonicity() const override
|
||||
{
|
||||
return FunctionUnaryArithmeticMonotonicity<Name>::has();
|
||||
|
@ -1,60 +0,0 @@
|
||||
#include <DataTypes/DataTypesNumber.h>
|
||||
#include <Functions/FunctionFactory.h>
|
||||
#include <Functions/IFunction.h>
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
#include <llvm/IR/IRBuilder.h>
|
||||
#endif
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int LOGICAL_ERROR;
|
||||
extern const int ILLEGAL_TYPE_OF_ARGUMENT;
|
||||
}
|
||||
|
||||
class FunctionSomething : public IFunction
|
||||
{
|
||||
public:
|
||||
static constexpr auto name = "something";
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
bool isCompilableImpl(const DataTypes & types) const override
|
||||
{
|
||||
return types.size() == 2 && types[0]->equals(*types[1]);
|
||||
}
|
||||
|
||||
llvm::Value * compileImpl(llvm::IRBuilderBase & builder, const DataTypes & types, ValuePlaceholders values) const override
|
||||
{
|
||||
if (types[0]->equals(DataTypeFloat32{}) || types[0]->equals(DataTypeFloat64{}))
|
||||
return static_cast<llvm::IRBuilder<>&>(builder).CreateFAdd(values[0](), values[1]());
|
||||
return static_cast<llvm::IRBuilder<>&>(builder).CreateAdd(values[0](), values[1]());
|
||||
}
|
||||
#endif
|
||||
|
||||
static FunctionPtr create(const Context &) { return std::make_shared<FunctionSomething>(); }
|
||||
|
||||
String getName() const override { return name; }
|
||||
|
||||
size_t getNumberOfArguments() const override { return 2; }
|
||||
|
||||
bool useDefaultImplementationForConstants() const override { return true; }
|
||||
|
||||
DataTypePtr getReturnTypeImpl(const DataTypes & types) const override { return types[0]; }
|
||||
|
||||
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result) override
|
||||
{
|
||||
throw Exception("should've used the jitted version", ErrorCodes::NOT_IMPLEMENTED);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void registerFunctionsLLVMTest(FunctionFactory & factory)
|
||||
{
|
||||
factory.registerFunction<FunctionSomething>();
|
||||
}
|
||||
|
||||
}
|
@ -93,6 +93,10 @@ struct RoundToExp2Impl
|
||||
{
|
||||
return roundDownToPowerOfTwo<T>(x);
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
static constexpr bool compilable = false;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@ -120,6 +124,10 @@ struct RoundDurationImpl
|
||||
: (x < 36000 ? 18000
|
||||
: 36000))))))))))))));
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
static constexpr bool compilable = false;
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename A>
|
||||
@ -137,6 +145,10 @@ struct RoundAgeImpl
|
||||
: (x < 55 ? 45
|
||||
: 55)))));
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
static constexpr bool compilable = false;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
@ -42,7 +42,6 @@ void registerFunctionsGeo(FunctionFactory &);
|
||||
void registerFunctionsCharset(FunctionFactory &);
|
||||
void registerFunctionsNull(FunctionFactory &);
|
||||
void registerFunctionsFindCluster(FunctionFactory &);
|
||||
void registerFunctionsLLVMTest(FunctionFactory &);
|
||||
|
||||
|
||||
void registerFunctions()
|
||||
@ -80,7 +79,6 @@ void registerFunctions()
|
||||
registerFunctionsCharset(factory);
|
||||
registerFunctionsNull(factory);
|
||||
registerFunctionsFindCluster(factory);
|
||||
registerFunctionsLLVMTest(factory);
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user