Skip to content

Commit

Permalink
xsimd plugged
Browse files Browse the repository at this point in the history
  • Loading branch information
JohanMabille committed Sep 20, 2017
1 parent d53c519 commit 59c0906
Show file tree
Hide file tree
Showing 13 changed files with 538 additions and 133 deletions.
8 changes: 8 additions & 0 deletions CMakeLists.txt
Expand Up @@ -77,6 +77,7 @@ set(XTENSOR_HEADERS

OPTION(XTENSOR_ENABLE_ASSERT "xtensor bound check" OFF)
OPTION(XTENSOR_CHECK_DIMENSION "xtensor dimension check" OFF)
OPTION(XTENSOR_USE_XSIMD "simd acceleration for xtensor" OFF)
OPTION(BUILD_TESTS "xtensor test suite" OFF)
OPTION(BUILD_BENCHMARK "xtensor benchmark" OFF)
OPTION(DOWNLOAD_GTEST "build gtest from downloaded sources" OFF)
Expand All @@ -94,6 +95,13 @@ if(XTENSOR_CHECK_DIMENSION)
add_definitions(-DXTENSOR_ENABLE_CHECK_DIMENSION)
endif()

if(XTENSOR_USE_XSIMD)
MESSAGE(STATUS "compiling with simd acceleration")
add_definitions(-DXTENSOR_USE_XSIMD)
find_package(xsimd REQUIRED)
include_directories(${xsimd_INCLUDE_DIRS})
endif()

if(DEFAULT_COLUMN_MAJOR)
add_definitions(-DDEFAULT_LAYOUT=layout_type::column_major)
endif()
Expand Down
43 changes: 38 additions & 5 deletions include/xtensor/xassign.hpp
Expand Up @@ -79,7 +79,7 @@ namespace xt
* trivial_assigner *
********************/

template <bool index_assign>
template <bool simd_assign>
struct trivial_assigner
{
template <class E1, class E2>
Expand All @@ -103,6 +103,19 @@ namespace xt
{
return false;
}

template <class E, class = void_t<int>>
struct forbid_simd_assign
{
static constexpr bool value = true;
};

template <class E>
struct forbid_simd_assign<E,
void_t<decltype(std::declval<E>().template load_simd<aligned_mode>(typename E::size_type(0)))>>
{
static constexpr bool value = false;
};
}

template <class E1, class E2>
Expand All @@ -115,7 +128,11 @@ namespace xt
if (trivial_broadcast)
{
constexpr bool contiguous_layout = E1::contiguous_layout && E2::contiguous_layout;
trivial_assigner<contiguous_layout>::run(de1, de2);
constexpr bool same_type = std::is_same<typename E1::value_type, typename E2::value_type>::value;
constexpr bool simd_size = xsimd::simd_traits<typename E1::value_type>::size > 1;
constexpr bool forbid_simd = detail::forbid_simd_assign<E2>::value;
constexpr bool simd_assign = contiguous_layout && same_type && simd_size && !forbid_simd;
trivial_assigner<simd_assign>::run(de1, de2);
}
else
{
Expand Down Expand Up @@ -240,13 +257,29 @@ namespace xt
* trivial_assigner implementation *
***********************************/

template <bool index_assign>
template <bool simd_assign>
template <class E1, class E2>
inline void trivial_assigner<index_assign>::run(E1& e1, const E2& e2)
inline void trivial_assigner<simd_assign>::run(E1& e1, const E2& e2)
{
using lhs_align_mode = xsimd::container_alignment_t<E1>;
constexpr bool is_aligned = std::is_same<lhs_align_mode, aligned_mode>::value;
using rhs_align_mode = std::conditional_t<is_aligned, inner_aligned_mode, unaligned_mode>;
using value_type = std::common_type_t<typename E1::value_type, typename E2::value_type>;
using simd_type = xsimd::simd_type<value_type>;
using size_type = typename E1::size_type;
size_type size = e1.size();
for (size_type i = 0; i < size; ++i)
size_type simd_size = simd_type::size;
size_type align_begin = is_aligned ? 0 : xsimd::get_alignment_offset(&(e1.data()), size, simd_size);
size_type align_end = align_begin + ((size - align_begin) &~(simd_size - 1));
for (size_type i = 0; i < align_begin; ++i)
{
e1.data_element(i) = e2.data_element(i);
}
for (size_type i = align_begin; i < align_end; i += simd_size)
{
e1.template store_simd<lhs_align_mode, simd_type>(i, e2.template load_simd<rhs_align_mode, simd_type>(i));
}
for (size_type i = align_end; i < size; ++i)
{
e1.data_element(i) = e2.data_element(i);
}
Expand Down
4 changes: 2 additions & 2 deletions include/xtensor/xbuilder.hpp
Expand Up @@ -188,8 +188,8 @@ namespace xt
template <class It>
inline T operator()(const It& /*begin*/, const It& end) const
{
using value_type = typename std::iterator_traits<It>::value_type;
return *(end - 1) == *(end - 2) + value_type(m_k) ? T(1) : T(0);
using lvalue_type = typename std::iterator_traits<It>::value_type;
return *(end - 1) == *(end - 2) + lvalue_type(m_k) ? T(1) : T(0);
}

private:
Expand Down
5 changes: 5 additions & 0 deletions include/xtensor/xcomplex.hpp
Expand Up @@ -170,10 +170,15 @@ namespace xt
{
using argument_type = T;
using result_type = decltype(detail::conj(std::declval<T>()));
using simd_value_type = xsimd::simd_type<T>; \
constexpr result_type operator()(const T& t) const
{
return detail::conj(t);
}
constexpr simd_value_type simd_apply(const simd_value_type& t) const
{
return detail::conj(t);
}
};
}

Expand Down
23 changes: 23 additions & 0 deletions include/xtensor/xcontainer.hpp
Expand Up @@ -61,6 +61,7 @@ namespace xt
using const_pointer = typename container_type::const_pointer;
using size_type = typename container_type::size_type;
using difference_type = typename container_type::difference_type;
using simd_value_type = xsimd::simd_type<value_type>;

using shape_type = typename inner_types::shape_type;
using strides_type = typename inner_types::strides_type;
Expand All @@ -76,6 +77,8 @@ namespace xt

static constexpr layout_type static_layout = inner_types::layout;
static constexpr bool contiguous_layout = static_layout != layout_type::dynamic;
using data_alignment = xsimd::container_alignment<container_type>;
using simd_type = xsimd::simd_type<value_type>;

size_type size() const noexcept;

Expand Down Expand Up @@ -133,6 +136,10 @@ namespace xt
reference data_element(size_type i);
const_reference data_element(size_type i) const;

template <class align, class simd = simd_value_type>
void store_simd(size_type i, const simd& e);
template <class align, class simd = simd_value_type>
simd load_simd(size_type i) const;

template <layout_type L>
using layout_iterator = typename iterable_base::template layout_iterator<L>;
Expand Down Expand Up @@ -1055,6 +1062,22 @@ namespace xt
return data()[i];
}

template <class D>
template <class alignment, class simd>
inline void xcontainer<D>::store_simd(size_type i, const simd& e)
{
using align_mode = driven_align_mode_t<alignment, data_alignment>;
xsimd::store_simd<value_type, typename simd::value_type>(&(data()[i]), e, align_mode());
}

template <class D>
template <class alignment, class simd>
inline auto xcontainer<D>::load_simd(size_type i) const -> simd
{
using align_mode = driven_align_mode_t<alignment, data_alignment>;
return xsimd::load_simd<value_type, typename simd::value_type>(&(data()[i]), align_mode());
}

/*************************************
* xstrided_container implementation *
*************************************/
Expand Down
37 changes: 36 additions & 1 deletion include/xtensor/xfunction.hpp
Expand Up @@ -21,6 +21,7 @@
#include "xiterable.hpp"
#include "xlayout.hpp"
#include "xscalar.hpp"
#include "xtensor_simd.hpp"
#include "xutils.hpp"

namespace xt
Expand Down Expand Up @@ -79,6 +80,20 @@ namespace xt

template <class... Args>
using common_value_type_t = typename common_value_type<Args...>::type;

template <class F, class R, class = void_t<int>>
struct simd_return_type
{
};

template <class F, class R>
struct simd_return_type<F, R, void_t<decltype(&F::simd_apply)>>
{
using type = R;
};

template <class F, class R>
using simd_return_type_t = typename simd_return_type<F, R>::type;
}

template <class F, class R, class... CT>
Expand Down Expand Up @@ -132,7 +147,7 @@ namespace xt
using const_pointer = const value_type*;
using size_type = detail::common_size_type_t<std::decay_t<CT>...>;
using difference_type = detail::common_difference_type_t<std::decay_t<CT>...>;

using simd_value_type = xsimd::simd_type<value_type>;
using iterable_base = xconst_iterable<xfunction<F, R, CT...>>;
using inner_shape_type = typename iterable_base::inner_shape_type;
using shape_type = inner_shape_type;
Expand Down Expand Up @@ -234,6 +249,9 @@ namespace xt
template <class UT = self_type, class = typename std::enable_if<UT::only_scalar::value>::type>
operator value_type() const;

template <class align, class simd = simd_value_type>
detail::simd_return_type_t<functor_type, simd> load_simd(size_type i) const;

private:

template <std::size_t... I>
Expand All @@ -248,6 +266,9 @@ namespace xt
template <std::size_t... I>
const_reference data_element_impl(std::index_sequence<I...>, size_type i) const;

template <class align, class simd, std::size_t... I>
simd load_simd_impl(std::index_sequence<I...>, size_type i) const;

template <class Func, std::size_t... I>
const_stepper build_stepper(Func&& f, std::index_sequence<I...>) const noexcept;

Expand Down Expand Up @@ -655,6 +676,13 @@ namespace xt
return operator()();
}

template <class F, class R, class... CT>
template <class align, class simd>
inline auto xfunction<F, R, CT...>::load_simd(size_type i) const -> detail::simd_return_type_t<functor_type, simd>
{
return load_simd_impl<align, simd>(std::make_index_sequence<sizeof...(CT)>(), i);
}

template <class F, class R, class... CT>
template <std::size_t... I>
inline layout_type xfunction<F, R, CT...>::layout_impl(std::index_sequence<I...>) const noexcept
Expand Down Expand Up @@ -683,6 +711,13 @@ namespace xt
return m_f((std::get<I>(m_e).data_element(i))...);
}

template <class F, class R, class... CT>
template <class align, class simd, std::size_t... I>
inline auto xfunction<F, R, CT...>::load_simd_impl(std::index_sequence<I...>, size_type i) const -> simd
{
return m_f.simd_apply((std::get<I>(m_e).template load_simd<align, simd>(i))...);
}

template <class F, class R, class... CT>
template <class Func, std::size_t... I>
inline auto xfunction<F, R, CT...>::build_stepper(Func&& f, std::index_sequence<I...>) const noexcept -> const_stepper
Expand Down

0 comments on commit 59c0906

Please sign in to comment.