diff --git a/include/xtensor/views/xstrided_view.hpp b/include/xtensor/views/xstrided_view.hpp index 3faff70c8..b0fe2c6e0 100644 --- a/include/xtensor/views/xstrided_view.hpp +++ b/include/xtensor/views/xstrided_view.hpp @@ -179,8 +179,13 @@ namespace xt using simd_value_type = xt_simd::simd_type; using bool_load_type = typename base_type::bool_load_type; + // load_simd/store_simd take the address of the flat storage, which requires the + // storage to expose lvalue references (not the case for lazy expressions wrapped + // in a flat_expression_adaptor). static constexpr bool provides_simd_interface = has_simd_interface::value - && L != layout_type::dynamic; + && L != layout_type::dynamic + && std::is_lvalue_reference_v< + decltype(std::declval()[0])>; template xstrided_view(CTA&& e, SA&& shape, strides_type&& strides, std::size_t offset, layout_type layout) noexcept; diff --git a/test/test_xstrided_view.cpp b/test/test_xstrided_view.cpp index 5b8f8c01d..b916d2473 100644 --- a/test/test_xstrided_view.cpp +++ b/test/test_xstrided_view.cpp @@ -723,6 +723,29 @@ namespace xt EXPECT_TRUE(std::equal(nv.shape().begin(), nv.shape().end(), expected_shape.begin())); } + TEST(xstrided_view, reshape_view_lazy_expression) + { + const std::size_t G = 8, N = 4; + xtensor w = xt::arange(G) + 1.0; + xtensor Phi = 3.0 * xt::ones({G, N}); + + // reshape_view over a lazy expression must not enable the SIMD assign path, + // which takes the address of the (computed) flat storage. + auto col = xt::reshape_view(w * w, {G, std::size_t(1)}); + xtensor out = Phi * col; + +#if XTENSOR_USE_XSIMD + using lazy_traits = xassign_traits, decltype(Phi * col)>; + EXPECT_FALSE(lazy_traits::simd_linear_assign()); + + auto colc = xt::reshape_view(w, {G, std::size_t(1)}); + using cont_traits = xassign_traits, decltype(Phi * colc)>; + EXPECT_TRUE(cont_traits::simd_linear_assign()); +#endif + + EXPECT_EQ(108.0, out(5, 2)); + } + TEST(xstrided_view, reshape_view_assign) { xarray xa = {{1, 2, 3}, {4, 5, 6}};