Skip to content

Commit a5ac6b5

Browse files
Provide batch_constant and batch_bool_constant, and use them to specialize the select function
in SSE4 and AVX, it's possible to pass an immediate to the blending intrinsic instead of a register. Provide the required support in terms of batch_constant and batch_bool_constant, and fallback to the vector version otherwise.
1 parent 70cc3f1 commit a5ac6b5

File tree

12 files changed

+435
-4
lines changed

12 files changed

+435
-4
lines changed

docs/source/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ This software is licensed under the BSD-3-Clause license. See the LICENSE file f
7777
api/instr_macros
7878
api/batch_index
7979
api/data_transfer
80+
api/batch_manip
8081
api/math_index
8182
api/aligned_allocator
8283

include/xsimd/types/xsimd_avx_double.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,13 @@ namespace xsimd
658658
return _mm256_blendv_pd(b, a, cond);
659659
}
660660

661+
template<bool... Values>
662+
static batch_type select(const batch_bool_constant<value_type, Values...>&, const batch_type& a, const batch_type& b)
663+
{
664+
constexpr int mask = batch_bool_constant<value_type, Values...>::mask();
665+
return _mm256_blend_pd(b, a, mask);
666+
}
667+
661668
static batch_bool_type isnan(const batch_type& x)
662669
{
663670
return _mm256_cmp_pd(x, x, _CMP_UNORD_Q);

include/xsimd/types/xsimd_avx_float.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -706,6 +706,13 @@ namespace xsimd
706706
return _mm256_blendv_ps(b, a, cond);
707707
}
708708

709+
template<bool... Values>
710+
static batch_type select(const batch_bool_constant<value_type, Values...>& cond, const batch_type& a, const batch_type& b)
711+
{
712+
constexpr int mask = batch_bool_constant<value_type, Values...>::mask();
713+
return _mm256_blend_ps(b, a, mask);
714+
}
715+
709716
static batch_bool_type isnan(const batch_type& x)
710717
{
711718
return _mm256_cmp_ps(x, x, _CMP_UNORD_Q);

include/xsimd/types/xsimd_base.hpp

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "../memory/xsimd_alignment.hpp"
2626
#include "xsimd_utils.hpp"
2727
#include "xsimd_base_bool.hpp"
28+
#include "xsimd_base_constant.hpp"
2829

2930
namespace xsimd
3031
{
@@ -212,7 +213,7 @@ namespace xsimd
212213
simd_batch(simd_batch&&) = default;
213214
simd_batch& operator=(simd_batch&&) = default;
214215

215-
simd_batch(storage_type value);
216+
constexpr simd_batch(storage_type value);
216217

217218
using char_itype =
218219
typename std::conditional<std::is_signed<char>::value, int8_t, uint8_t>::type;
@@ -671,7 +672,7 @@ namespace xsimd
671672
*****************************/
672673

673674
template <class X>
674-
inline simd_batch<X>::simd_batch(storage_type value)
675+
constexpr inline simd_batch<X>::simd_batch(storage_type value)
675676
: m_value(value)
676677
{
677678
}
@@ -1700,6 +1701,28 @@ namespace xsimd
17001701
return kernel::select(cond(), a(), b());
17011702
}
17021703

1704+
/**
1705+
* @ingroup simd_batch_miscellaneous
1706+
*
1707+
* Ternary operator for batches: selects values from the batches \c a or \c b
1708+
* depending on the boolean values in the constant batch \c cond. Equivalent to
1709+
* \code{.cpp}
1710+
* for(std::size_t i = 0; i < N; ++i)
1711+
* res[i] = cond[i] ? a[i] : b[i];
1712+
* \endcode
1713+
* @param cond constant batch condition.
1714+
* @param a batch values for truthy condition.
1715+
* @param b batch value for falsy condition.
1716+
* @return the result of the selection.
1717+
*/
1718+
template <class X, bool... Masks>
1719+
inline batch_type_t<X> select(const batch_bool_constant<typename simd_batch_traits<X>::value_type, Masks...>& cond, const simd_base<X>& a, const simd_base<X>& b)
1720+
{
1721+
using value_type = typename simd_batch_traits<X>::value_type;
1722+
using kernel = detail::batch_kernel<value_type, simd_batch_traits<X>::size>;
1723+
return kernel::select(cond, a(), b());
1724+
}
1725+
17031726
/**
17041727
* Determines if the scalars in the given batch \c x are NaN values.
17051728
* @param x batch of floating point values.
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/***************************************************************************
2+
* Copyright (c) Serge Guelton *
3+
* Copyright (c) QuantStack *
4+
* *
5+
* Distributed under the terms of the BSD 3-Clause License. *
6+
* *
7+
* The full license is in the file LICENSE, distributed with this software. *
8+
****************************************************************************/
9+
10+
#ifndef XSIMD_BASE_CONSTANT_HPP
11+
#define XSIMD_BASE_CONSTANT_HPP
12+
13+
namespace xsimd
14+
{
15+
template <class X>
16+
class simd_base;
17+
18+
template <class T, bool... Values>
19+
struct batch_bool_constant
20+
{
21+
static constexpr std::size_t size = sizeof...(Values);
22+
using value_type = bool;
23+
using batch_type =
24+
typename simd_batch_traits<batch<T, size>>::batch_bool_type;
25+
26+
batch_type operator()() const { return *this; }
27+
28+
operator batch_type() const { return {Values...}; }
29+
30+
bool operator[](size_t i) const
31+
{
32+
return std::array<value_type, size>{Values...}[i];
33+
}
34+
static constexpr int mask()
35+
{
36+
return mask_helper(0, static_cast<int>(Values)...);
37+
}
38+
39+
private:
40+
static constexpr int mask_helper(int acc) { return acc; }
41+
template <class... Tys>
42+
static constexpr int mask_helper(int acc, int mask, Tys... masks)
43+
{
44+
return mask_helper(acc | mask, (masks << 1)...);
45+
}
46+
};
47+
48+
template <class T, T... Values>
49+
struct batch_constant
50+
{
51+
static constexpr std::size_t size = sizeof...(Values);
52+
using value_type = T;
53+
using batch_type = batch<T, size>;
54+
55+
batch_type operator()() const { return *this; }
56+
57+
operator batch_type() const { return {Values...}; }
58+
59+
constexpr T operator[](size_t i) const
60+
{
61+
return std::array<value_type, size>{Values...}[i];
62+
}
63+
};
64+
65+
namespace detail
66+
{
67+
template <class G, std::size_t... Is>
68+
constexpr auto make_batch_constant(detail::index_sequence<Is...>)
69+
-> batch_constant<decltype(G::get(0, 0)),
70+
G::get(Is, sizeof...(Is))...>
71+
{
72+
return {};
73+
}
74+
template <class T, class G, std::size_t... Is>
75+
constexpr auto make_batch_bool_constant(detail::index_sequence<Is...>)
76+
-> batch_bool_constant<T, G::get(Is, sizeof...(Is))...>
77+
{
78+
return {};
79+
}
80+
template <class T, T value, std::size_t... Is>
81+
constexpr auto make_batch_constant(detail::index_sequence<Is...>)
82+
-> batch_constant<T, (Is, value)...>
83+
{
84+
return {};
85+
}
86+
template <class T, T value, std::size_t... Is>
87+
constexpr auto make_batch_bool_constant(detail::index_sequence<Is...>)
88+
-> batch_bool_constant<T, (Is, value)...>
89+
{
90+
return {};
91+
}
92+
} // namespace detail
93+
94+
template <class G, std::size_t N>
95+
constexpr auto make_batch_constant() -> decltype(
96+
detail::make_batch_constant<G>(detail::make_index_sequence<N>()))
97+
{
98+
return detail::make_batch_constant<G>(detail::make_index_sequence<N>());
99+
}
100+
101+
template <class T, class G, std::size_t N>
102+
constexpr auto make_batch_bool_constant()
103+
-> decltype(detail::make_batch_bool_constant<T, G>(
104+
detail::make_index_sequence<N>()))
105+
{
106+
return detail::make_batch_bool_constant<T, G>(
107+
detail::make_index_sequence<N>());
108+
}
109+
110+
} // namespace xsimd
111+
112+
#endif

include/xsimd/types/xsimd_fallback.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -917,6 +917,12 @@ namespace xsimd
917917
XSIMD_FALLBACK_MAPPING_LOOP(batch, (cond[i] ? a[i] : b[i]))
918918
}
919919

920+
template<bool... Values>
921+
static batch_type select(const batch_bool_constant<value_type, Values...>& cond, const batch_type& a, const batch_type& b)
922+
{
923+
XSIMD_FALLBACK_MAPPING_LOOP(batch, (cond[i] ? a[i] : b[i]))
924+
}
925+
920926
static batch_bool_type isnan(const batch_type& x)
921927
{
922928
XSIMD_FALLBACK_MAPPING_LOOP(batch_bool, std::isnan(x[i]))

include/xsimd/types/xsimd_sse_double.hpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,17 @@ namespace xsimd
629629
#endif
630630
}
631631

632+
template<bool... Values>
633+
static batch_type select(const batch_bool_constant<value_type, Values...>& cond, const batch_type& a, const batch_type& b)
634+
{
635+
#if XSIMD_X86_INSTR_SET >= XSIMD_X86_SSE4_1_VERSION
636+
constexpr int mask = batch_bool_constant<value_type, Values...>::mask();
637+
return _mm_blend_pd(b, a, mask);
638+
#else
639+
return select(cond(), a, b);
640+
#endif
641+
}
642+
632643
static batch_bool_type isnan(const batch_type& x)
633644
{
634645
return _mm_cmpunord_pd(x, x);

include/xsimd/types/xsimd_sse_float.hpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,18 @@ namespace xsimd
692692
#endif
693693
}
694694

695+
template<bool... Values>
696+
static batch_type select(const batch_bool_constant<value_type, Values...>& cond, const batch_type& a, const batch_type& b)
697+
{
698+
#if XSIMD_X86_INSTR_SET >= XSIMD_X86_SSE4_1_VERSION
699+
(void)cond;
700+
constexpr int mask = batch_bool_constant<value_type, Values...>::mask();
701+
return _mm_blend_ps(b, a, mask);
702+
#else
703+
return select((batch_bool_type)cond, a, b);
704+
#endif
705+
}
706+
695707
static batch_bool_type isnan(const batch_type& x)
696708
{
697709
return _mm_cmpunord_ps(x, x);

include/xsimd/types/xsimd_sse_int_base.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ namespace xsimd
7070
sse_int_batch();
7171
explicit sse_int_batch(T i);
7272
template <class... Args, class Enable = detail::is_array_initializer_t<T, N, Args...>>
73-
sse_int_batch(Args... args);
73+
constexpr sse_int_batch(Args... args);
7474
explicit sse_int_batch(const T* src);
7575
sse_int_batch(const T* src, aligned_mode);
7676
sse_int_batch(const T* src, unaligned_mode);
@@ -324,7 +324,7 @@ namespace xsimd
324324

325325
template <class T, std::size_t N>
326326
template <class... Args, class>
327-
inline sse_int_batch<T, N>::sse_int_batch(Args... args)
327+
constexpr inline sse_int_batch<T, N>::sse_int_batch(Args... args)
328328
: base_type(sse_detail::int_init(std::integral_constant<std::size_t, sizeof(T)>{}, args...))
329329
{
330330
}

test/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ set(XSIMD_TESTS
152152
test_batch_float.cpp
153153
test_batch_int.cpp
154154
test_bitwise_cast.cpp
155+
test_constant_batch.cpp
155156
test_complex_exponential.cpp
156157
test_complex_hyperbolic.cpp
157158
test_complex_power.cpp
@@ -166,6 +167,7 @@ set(XSIMD_TESTS
166167
test_poly_evaluation.cpp
167168
test_power.cpp
168169
test_rounding.cpp
170+
test_select.cpp
169171
test_trigonometric.cpp
170172
test_utils.hpp
171173
#[[ xsimd_api_test.hpp

0 commit comments

Comments
 (0)