diff --git a/src/Functions/if.cpp b/src/Functions/if.cpp index 7f1423cd434..7789fc51ed1 100644 --- a/src/Functions/if.cpp +++ b/src/Functions/if.cpp @@ -219,6 +219,36 @@ inline void fillConstantVector(const ArrayCond & cond, A a, const ArrayB & b, Ar } } +template +inline void fillConstantConstant(const ArrayCond & cond, A a, B b, ArrayResult & res) +{ + size_t size = cond.size(); + if constexpr (std::is_same_v || std::is_same_v || is_over_big_int) + { + alignas(64) const ResultType ab[2] = {static_cast(a), static_cast(b)}; + for (size_t i = 0; i < size; ++i) + { + /// Introduce memory access to avoid branch miss + res[i] = ab[!cond[i]]; + } + } + else if constexpr (std::is_same_v || std::is_same_v) + { + ResultType new_a = static_cast(a); + ResultType new_b = static_cast(b); + for (size_t i = 0; i < size; ++i) + { + /// Reuse new_a and new_b to achieve auto-vectorization + res[i] = cond[i] ? new_a : new_b; + } + } + else + { + for (size_t i = 0; i < size; ++i) + res[i] = cond[i] ? static_cast(a) : static_cast(b); + } +} + template struct NumIfImpl { @@ -261,9 +291,7 @@ struct NumIfImpl auto col_res = ColVecResult::create(size); ArrayResult & res = col_res->getData(); - /// TODO cast a and b only once - for (size_t i = 0; i < size; ++i) - res[i] = cond[i] ? static_cast(a) : static_cast(b); + fillConstantConstant(cond, a, b, res); return col_res; } }; @@ -312,8 +340,7 @@ struct NumIfImpl, Decimal, Decimal> auto col_res = ColVecResult::create(size, scale); ArrayResult & res = col_res->getData(); - for (size_t i = 0; i < size; ++i) - res[i] = cond[i] ? static_cast(a) : static_cast(b); + fillConstantConstant(cond, a, b, res); return col_res; } }; diff --git a/tests/performance/if.xml b/tests/performance/if.xml index b25218f553e..0f1dca91ac2 100644 --- a/tests/performance/if.xml +++ b/tests/performance/if.xml @@ -7,6 +7,18 @@ + with rand32() % 2 as x select if(x, materialize(1.234), materialize(2.456)) from numbers(100000000) format Null with rand32() % 2 as x, 1.234::Decimal64(3) as a, 2.456::Decimal64(3) as b select if(x, materialize(a), materialize(b)) from numbers(100000000) format Null + + + with rand32() % 2 as x, 1::Int8 as a, -1::Int8 as b select if(x, a, b) from numbers(100000000) format Null + with rand32() % 2 as x, 1::Int64 as a, -1::Int64 as b select if(x, a, b) from numbers(100000000) format Null + with rand32() % 2 as x, 1::Int32 as a, -1::Int32 as b select if(x, a, b) from numbers(100000000) format Null + with rand32() % 2 as x, 1::Decimal32(3) as a, -1::Decimal32(3) as b select if(x, a, b) from numbers(100000000) format Null + with rand32() % 2 as x, 1::Decimal64(3) as a, -1::Decimal64(3) as b select if(x, a, b) from numbers(100000000) format Null + with rand32() % 2 as x, 1::Decimal128(3) as a, -1::Decimal128(3) as b select if(x, a, b) from numbers(100000000) format Null + with rand32() % 2 as x, 1::Decimal256(3) as a, -1::Decimal256(3) as b select if(x, a, b) from numbers(100000000) format Null + with rand32() % 2 as x, 1::Int128 as a, -1::Int128 as b select if(x, a, b) from numbers(100000000) format Null + with rand32() % 2 as x, 1::Int256 as a, -1::Int256 as b select if(x, a, b) from numbers(100000000) format Null