Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions include/xsimd/arch/common/xsimd_common_memory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,25 @@ namespace xsimd
return buffer[i];
}

// first
template <class A, class T>
XSIMD_INLINE T first(batch<T, A> const& self, requires_arch<common>) noexcept
{
return get(self, 0, common {});
}

template <class A, class T>
XSIMD_INLINE T first(batch_bool<T, A> const& self, requires_arch<common>) noexcept
{
return get(self, 0, common {});
}

template <class A, class T>
XSIMD_INLINE auto first(batch<std::complex<T>, A> const& self, requires_arch<common>) noexcept -> typename batch<std::complex<T>, A>::value_type
{
return get(self, 0, common {});
}

// load
template <class A, class T>
XSIMD_INLINE batch_bool<T, A> load_unaligned(bool const* mem, batch_bool<T, A>, requires_arch<common>) noexcept
Expand Down
53 changes: 52 additions & 1 deletion include/xsimd/arch/xsimd_avx.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@

namespace xsimd
{

namespace kernel
{
using namespace types;
Expand Down Expand Up @@ -1861,6 +1860,58 @@ namespace xsimd
auto hi = _mm256_unpackhi_pd(self, other);
return _mm256_insertf128_pd(lo, _mm256_castpd256_pd128(hi), 1);
}

// first
template <class A>
XSIMD_INLINE float first(batch<float, A> const& self, requires_arch<avx>) noexcept
{
return _mm256_cvtss_f32(self);
}

template <class A>
XSIMD_INLINE double first(batch<double, A> const& self, requires_arch<avx>) noexcept
{
return _mm256_cvtsd_f64(self);
}

template <class A, class T, class = typename std::enable_if<std::is_integral<T>::value, void>::type>
XSIMD_INLINE T first(batch<T, A> const& self, requires_arch<avx>) noexcept
{
XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
{
return static_cast<T>(_mm256_cvtsi256_si32(self) & 0xFF);
}
else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
{
return static_cast<T>(_mm256_cvtsi256_si32(self) & 0xFFFF);
}
else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
{
return static_cast<T>(_mm256_cvtsi256_si32(self));
}
else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
{
__m128i low = _mm256_castsi256_si128(self);
return static_cast<T>(_mm_cvtsi128_si64(low));
}
else
{
assert(false && "unsupported arch/op combination");
return {};
}
}

template <class A, class T>
XSIMD_INLINE std::complex<T> first(batch<std::complex<T>, A> const& self, requires_arch<avx>) noexcept
{
return { first(self.real(), A {}), first(self.imag(), A {}) };
}

template <class A, class T>
XSIMD_INLINE bool first(batch_bool<T, A> const& self, requires_arch<avx>) noexcept
{
return first(batch<T, A>(self), A {});
}
}
}

Expand Down
51 changes: 51 additions & 0 deletions include/xsimd/arch/xsimd_avx512f.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2339,6 +2339,57 @@ namespace xsimd
2));
}

// first
template <class A>
XSIMD_INLINE float first(batch<float, A> const& self, requires_arch<avx512f>) noexcept
{
return _mm512_cvtss_f32(self);
}

template <class A>
XSIMD_INLINE double first(batch<double, A> const& self, requires_arch<avx512f>) noexcept
{
return _mm512_cvtsd_f64(self);
}

template <class A, class T, class = typename std::enable_if<std::is_integral<T>::value, void>::type>
XSIMD_INLINE T first(batch<T, A> const& self, requires_arch<avx512f>) noexcept
{
XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
{
return static_cast<T>(_mm512_cvtsi512_si32(self) & 0xFF);
}
else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
{
return static_cast<T>(_mm512_cvtsi512_si32(self) & 0xFFFF);
}
else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
{
return static_cast<T>(_mm512_cvtsi512_si32(self));
}
else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
{
return static_cast<T>(_mm_cvtsi128_si64(_mm512_castsi512_si128(self)));
}
else
{
assert(false && "unsupported arch/op combination");
return {};
}
}

template <class A, class T>
XSIMD_INLINE std::complex<T> first(batch<std::complex<T>, A> const& self, requires_arch<avx512f>) noexcept
{
return { first(self.real(), A {}), first(self.imag(), A {}) };
}

template <class A, class T>
XSIMD_INLINE bool first(batch_bool<T, A> const& self, requires_arch<avx512f>) noexcept
{
return first(batch<T, A>(self), A {});
}

}

}
Expand Down
51 changes: 51 additions & 0 deletions include/xsimd/arch/xsimd_sse2.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1782,6 +1782,57 @@ namespace xsimd
{
return _mm_unpacklo_pd(self, other);
}

// first
template <class A>
XSIMD_INLINE float first(batch<float, A> const& self, requires_arch<sse2>) noexcept
{
return _mm_cvtss_f32(self);
}

template <class A>
XSIMD_INLINE double first(batch<double, A> const& self, requires_arch<sse2>) noexcept
{
return _mm_cvtsd_f64(self);
}

template <class A, class T, class = typename std::enable_if<std::is_integral<T>::value, void>::type>
XSIMD_INLINE T first(batch<T, A> const& self, requires_arch<sse2>) noexcept
{
XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
{
return static_cast<T>(_mm_cvtsi128_si32(self) & 0xFF);
}
else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
{
return static_cast<T>(_mm_cvtsi128_si32(self) & 0xFFFF);
}
else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
{
return static_cast<T>(_mm_cvtsi128_si32(self));
}
else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
{
return static_cast<T>(_mm_cvtsi128_si64(self));
}
else
{
assert(false && "unsupported arch/op combination");
return {};
}
}

template <class A, class T>
XSIMD_INLINE std::complex<T> first(batch<std::complex<T>, A> const& self, requires_arch<sse2>) noexcept
{
return { first(self.real(), A {}), first(self.imag(), A {}) };
}

template <class A, class T>
XSIMD_INLINE bool first(batch_bool<T, A> const& self, requires_arch<sse2>) noexcept
{
return first(batch<T, A>(self), A {});
}
}
}

Expand Down
31 changes: 31 additions & 0 deletions include/xsimd/types/xsimd_batch.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,8 @@ namespace xsimd

XSIMD_INLINE T get(std::size_t i) const noexcept;

XSIMD_INLINE T first() const noexcept;

// comparison operators. Defined as friend to enable automatic
// conversion of parameters from scalar to batch, at the cost of using a
// proxy implementation from details::.
Expand Down Expand Up @@ -314,6 +316,8 @@ namespace xsimd

XSIMD_INLINE bool get(std::size_t i) const noexcept;

XSIMD_INLINE bool first() const noexcept;

// mask operations
XSIMD_INLINE uint64_t mask() const noexcept;
XSIMD_INLINE static batch_bool from_mask(uint64_t mask) noexcept;
Expand Down Expand Up @@ -405,6 +409,8 @@ namespace xsimd

XSIMD_INLINE value_type get(std::size_t i) const noexcept;

XSIMD_INLINE value_type first() const noexcept;

#ifdef XSIMD_ENABLE_XTL_COMPLEX
// xtl-related methods
template <bool i3ec>
Expand Down Expand Up @@ -693,6 +699,16 @@ namespace xsimd
return kernel::get(*this, i, A {});
}

/**
* Retrieve the first scalar element in this batch.
*/
template <class T, class A>
XSIMD_INLINE T batch<T, A>::first() const noexcept
{
detail::static_check_supported_config<T, A>();
return kernel::first(*this, A {});
}

/******************************
* batch comparison operators *
******************************/
Expand Down Expand Up @@ -1005,6 +1021,13 @@ namespace xsimd
return kernel::get(*this, i, A {});
}

template <class T, class A>
XSIMD_INLINE bool batch_bool<T, A>::first() const noexcept
{
detail::static_check_supported_config<T, A>();
return kernel::first(*this, A {});
}

/***********************************
* batch_bool comparison operators *
***********************************/
Expand Down Expand Up @@ -1077,6 +1100,7 @@ namespace xsimd
{
}


template <class T, class A>
template <class U, class... V, size_t I, size_t... Is>
XSIMD_INLINE auto batch_bool<T, A>::make_register(detail::index_sequence<I, Is...>, U u, V... v) noexcept -> register_type
Expand Down Expand Up @@ -1248,6 +1272,13 @@ namespace xsimd
return kernel::get(*this, i, A {});
}

template <class T, class A>
XSIMD_INLINE auto batch<std::complex<T>, A>::first() const noexcept -> value_type
{
detail::static_check_supported_config<std::complex<T>, A>();
return kernel::first(*this, A {});
}

/**************************************
* batch<complex> xtl-related methods *
**************************************/
Expand Down
11 changes: 11 additions & 0 deletions test/test_batch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,12 @@ struct batch_test
}
}

void test_first_element() const
{
batch_type res = batch_lhs();
CHECK_EQ(res.first(), lhs[0]);
}

void test_arithmetic() const
{
// +batch
Expand Down Expand Up @@ -934,6 +940,11 @@ TEST_CASE_TEMPLATE("[batch]", B, BATCH_TYPES)
Test.test_access_operator();
}

SUBCASE("first element")
{
Test.test_first_element();
}

SUBCASE("arithmetic")
{
Test.test_arithmetic();
Expand Down
8 changes: 8 additions & 0 deletions test/test_batch_complex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,12 @@ struct batch_complex_test
}
}

void test_first_element() const
{
batch_type res = batch_lhs();
CHECK_EQ(res.first(), lhs[0]);
}

void test_arithmetic() const
{
// +batch
Expand Down Expand Up @@ -675,6 +681,8 @@ TEST_CASE_TEMPLATE("[xsimd complex batches]", B, BATCH_COMPLEX_TYPES)

SUBCASE("access_operator") { Test.test_access_operator(); }

SUBCASE("first element") { Test.test_first_element(); }

SUBCASE("arithmetic") { Test.test_arithmetic(); }

SUBCASE("computed_assignment") { Test.test_computed_assignment(); }
Expand Down
Loading