#include #include #if defined(__SSE2__) # define LIBDIVIDE_SSE2 1 #endif #include namespace DB { namespace ErrorCodes { extern const int ILLEGAL_DIVISION; } namespace { /// Optimizations for integer division by a constant. template struct DivideIntegralByConstantImpl : BinaryOperation> { using ResultType = typename DivideIntegralImpl::ResultType; static const constexpr bool allow_fixed_string = false; static NO_INLINE void vectorConstant(const A * __restrict a_pos, B b, ResultType * __restrict c_pos, size_t size) { #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsign-compare" /// Division by -1. By the way, we avoid FPE by division of the largest negative number by -1. /// And signed integer overflow is well defined in C++20. if (unlikely(is_signed_v && b == -1)) { for (size_t i = 0; i < size; ++i) c_pos[i] = -a_pos[i]; return; } /// Division with too large divisor. if (unlikely(b > std::numeric_limits::max() || (std::is_signed_v && std::is_signed_v && b < std::numeric_limits::lowest()))) { for (size_t i = 0; i < size; ++i) c_pos[i] = 0; return; } #pragma GCC diagnostic pop if (unlikely(static_cast(b) == 0)) throw Exception("Division by zero", ErrorCodes::ILLEGAL_DIVISION); libdivide::divider divider(b); const A * a_end = a_pos + size; #if defined(__SSE2__) static constexpr size_t values_per_sse_register = 16 / sizeof(A); const A * a_end_sse = a_pos + size / values_per_sse_register * values_per_sse_register; while (a_pos < a_end_sse) { _mm_storeu_si128(reinterpret_cast<__m128i *>(c_pos), _mm_loadu_si128(reinterpret_cast(a_pos)) / divider); a_pos += values_per_sse_register; c_pos += values_per_sse_register; } #endif while (a_pos < a_end) { *c_pos = *a_pos / divider; ++a_pos; ++c_pos; } } }; /** Specializations are specified for dividing numbers of the type UInt64 and UInt32 by the numbers of the same sign. * Can be expanded to all possible combinations, but more code is needed. */ } template <> struct BinaryOperationImpl> : DivideIntegralByConstantImpl {}; template <> struct BinaryOperationImpl> : DivideIntegralByConstantImpl {}; template <> struct BinaryOperationImpl> : DivideIntegralByConstantImpl {}; template <> struct BinaryOperationImpl> : DivideIntegralByConstantImpl {}; template <> struct BinaryOperationImpl> : DivideIntegralByConstantImpl {}; template <> struct BinaryOperationImpl> : DivideIntegralByConstantImpl {}; template <> struct BinaryOperationImpl> : DivideIntegralByConstantImpl {}; template <> struct BinaryOperationImpl> : DivideIntegralByConstantImpl {}; template <> struct BinaryOperationImpl> : DivideIntegralByConstantImpl {}; template <> struct BinaryOperationImpl> : DivideIntegralByConstantImpl {}; template <> struct BinaryOperationImpl> : DivideIntegralByConstantImpl {}; template <> struct BinaryOperationImpl> : DivideIntegralByConstantImpl {}; template <> struct BinaryOperationImpl> : DivideIntegralByConstantImpl {}; template <> struct BinaryOperationImpl> : DivideIntegralByConstantImpl {}; template <> struct BinaryOperationImpl> : DivideIntegralByConstantImpl {}; template <> struct BinaryOperationImpl> : DivideIntegralByConstantImpl {}; struct NameIntDiv { static constexpr auto name = "intDiv"; }; using FunctionIntDiv = BinaryArithmeticOverloadResolver; void registerFunctionIntDiv(FunctionFactory & factory) { factory.registerFunction(); } }