Skip to content

Commit 33a7e99

Browse files
committed
Add bitwise-shift batch constant api
1 parent 6842624 commit 33a7e99

2 files changed

Lines changed: 83 additions & 17 deletions

File tree

include/xsimd/types/xsimd_api.hpp

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,41 @@ namespace xsimd
353353
return kernel::bitwise_cast<A>(x, batch<T_out, A> {}, A {});
354354
}
355355

356+
namespace detail
357+
{
358+
// Detection for kernel overloads accepting ``batch_constant`` in ``bitwise_lshift``
359+
// directly (or in a parent register function).
360+
// The ``batch_constant`` overload is a rare but useful optimization.
361+
// Running the detection here is less error prone than to add a fallback to all
362+
// architectures.
363+
364+
template <class A, class B, class C, class = void>
365+
struct has_bitwise_lshift_batch_const : std::false_type
366+
{
367+
};
368+
369+
template <class A, class B, class C>
370+
struct has_bitwise_lshift_batch_const<A, B, C,
371+
void_t<decltype(kernel::bitwise_lshift<A>(std::declval<B>(), std::declval<C>(), A {}))>>
372+
: std::true_type
373+
{
374+
};
375+
376+
template <class A, class T, T... Values>
377+
XSIMD_INLINE batch<T, A> bitwise_lshift_batch_const(batch<T, A> const& x, batch_constant<T, A, Values...> shift, std::true_type) noexcept
378+
{
379+
// Optimized ``batch_constant`` implementation
380+
return kernel::bitwise_lshift<A>(x, shift, A {});
381+
}
382+
383+
template <class A, class T, T... Values>
384+
XSIMD_INLINE batch<T, A> bitwise_lshift_batch_const(batch<T, A> const& x, batch_constant<T, A, Values...> shift, std::false_type) noexcept
385+
{
386+
// Fallback to regular run-time implementation
387+
return kernel::bitwise_lshift<A>(x, shift.as_batch(), A {});
388+
}
389+
}
390+
356391
/**
357392
* @ingroup batch_bitwise
358393
*
@@ -367,17 +402,24 @@ namespace xsimd
367402
detail::static_check_supported_config<T, A>();
368403
return kernel::bitwise_lshift<A>(x, shift, A {});
369404
}
405+
template <size_t shift, class T, class A>
406+
XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& x) noexcept
407+
{
408+
detail::static_check_supported_config<T, A>();
409+
return kernel::bitwise_lshift<shift, A>(x, A {});
410+
}
370411
template <class T, class A>
371412
XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& x, batch<T, A> const& shift) noexcept
372413
{
373414
detail::static_check_supported_config<T, A>();
374415
return kernel::bitwise_lshift<A>(x, shift, A {});
375416
}
376-
template <size_t shift, class T, class A>
377-
XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& x) noexcept
417+
template <class T, class A, T... Values>
418+
XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& x, batch_constant<T, A, Values...> shift) noexcept
378419
{
379420
detail::static_check_supported_config<T, A>();
380-
return kernel::bitwise_lshift<shift, A>(x, A {});
421+
using has_batch_const_impl = detail::has_bitwise_lshift_batch_const<A, decltype(x), decltype(shift)>;
422+
return detail::bitwise_lshift_batch_const<A>(x, shift, has_batch_const_impl {});
381423
}
382424

383425
/**

test/test_xsimd_api.cpp

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ struct xsimd_api_integral_types_functions
351351
{
352352
using value_type = typename scalar_type<T>::type;
353353

354-
void test_bitwise_lshift()
354+
void test_bitwise_lshift_single()
355355
{
356356
constexpr int shift = 3;
357357
value_type val0(12);
@@ -364,6 +364,33 @@ struct xsimd_api_integral_types_functions
364364
CHECK_EQ(extract(cr), r);
365365
}
366366

367+
template <typename U = T>
368+
void test_bitwise_lshift_multiple(typename std::enable_if<!std::is_integral<U>::value, int>::type = 0)
369+
{
370+
#ifndef XSIMD_NO_SUPPORTED_ARCHITECTURE
371+
constexpr auto Max = static_cast<value_type>(std::numeric_limits<value_type>::digits);
372+
constexpr auto max_batch = xsimd::make_batch_constant<value_type, Max>();
373+
constexpr auto shifts = xsimd::make_iota_batch_constant<value_type>() % max_batch;
374+
375+
auto shifted = xsimd::bitwise_lshift(T(1), shifts.as_batch());
376+
for (std::size_t i = 0; i < shifts.size; ++i)
377+
{
378+
CHECK_EQ(shifted.get(i), 1 << shifts.get(i));
379+
}
380+
381+
auto shifted_cst = xsimd::bitwise_lshift(T(1), shifts);
382+
for (std::size_t i = 0; i < shifts.size; ++i)
383+
{
384+
CHECK_EQ(shifted_cst.get(i), 1 << shifts.get(i));
385+
}
386+
#endif
387+
}
388+
389+
template <typename U = T>
390+
void test_bitwise_lshift_multiple(typename std::enable_if<std::is_integral<U>::value, int>::type = 0)
391+
{
392+
}
393+
367394
void test_bitwise_rshift()
368395
{
369396
constexpr int shift = 3;
@@ -426,9 +453,14 @@ TEST_CASE_TEMPLATE("[xsimd api | integral types functions]", B, INTEGRAL_TYPES)
426453
{
427454
xsimd_api_integral_types_functions<B> Test;
428455

429-
SUBCASE("bitwise_lshift")
456+
SUBCASE("test_bitwise_lshift_single")
457+
{
458+
Test.test_bitwise_lshift_single();
459+
}
460+
461+
SUBCASE("bitwise_lshift_multiple")
430462
{
431-
Test.test_bitwise_lshift();
463+
Test.test_bitwise_lshift_multiple();
432464
}
433465

434466
SUBCASE("bitwise_rshift")
@@ -502,17 +534,9 @@ struct xsimd_api_float_types_functions
502534
}
503535
void test_atan2()
504536
{
505-
{
506-
value_type val0(0);
507-
value_type val1(1);
508-
CHECK_EQ(extract(xsimd::atan2(T(val0), T(val1))), std::atan2(val0, val1));
509-
}
510-
511-
{
512-
value_type val0(1);
513-
value_type val1(0);
514-
CHECK_EQ(extract(xsimd::atan2(T(val0), T(val1))), std::atan2(val0, val1));
515-
}
537+
value_type val0(0);
538+
value_type val1(1);
539+
CHECK_EQ(extract(xsimd::atan2(T(val0), T(val1))), std::atan2(val0, val1));
516540
}
517541
void test_atanh()
518542
{

0 commit comments

Comments
 (0)