diff --git a/core/src/Kokkos_CopyViews.hpp b/core/src/Kokkos_CopyViews.hpp index 08f6ba8d696..236d3ed7a51 100644 --- a/core/src/Kokkos_CopyViews.hpp +++ b/core/src/Kokkos_CopyViews.hpp @@ -3407,49 +3407,75 @@ inline void realloc( namespace Kokkos { namespace Impl { -// Deduce Mirror Types +// Actual mirror view type +template +struct MirrorViewType; + +// Dummy mirror view type that contains nothing +template +struct MirrorViewType { + using src_view_type = void; + using memory_space = void; + using array_layout = void; + using data_type = void; + using dest_view_type = void; + using view_type = void; + static constexpr bool is_same_namespace = false; + static constexpr bool is_same_data_type = false; + static constexpr bool is_same = false; +}; + +// Actual mirror view type template struct MirrorViewType { // The incoming view_type using src_view_type = typename Kokkos::View; + // The memory space for the mirror view using memory_space = typename Space::memory_space; - // Check whether it is the same memory space - enum { - is_same_memspace = - std::is_same::value - }; + + // The execution space for the mirror view + using execution_space = typename Space::execution_space; + // The array_layout using array_layout = typename src_view_type::array_layout; + // The data type (we probably want it non-const since otherwise we can't even - // deep_copy to it. + // deep_copy to it) using data_type = typename src_view_type::non_const_data_type; + + // The hooks policy + using hooks_policy = typename src_view_type::traits::hooks_policy; + // The destination view type if it is not the same memory space - using dest_view_type = Kokkos::View; - // If it is the same memory_space return the existsing view_type - // This will also keep the unmanaged trait if necessary - using view_type = - std::conditional_t; -}; + // If the memory space is the host memory space, use View::HostMirror + using dest_view_type = std::conditional_t< + std::is_same_v, + typename Kokkos::View::HostMirror, + typename Kokkos::View, hooks_policy>>; + -template -struct MirrorType { - // The incoming view_type - using src_view_type = typename Kokkos::View; - // The memory space for the mirror view - using memory_space = typename Space::memory_space; // Check whether it is the same memory space enum { is_same_memspace = std::is_same::value }; - // The array_layout - using array_layout = typename src_view_type::array_layout; - // The data type (we probably want it non-const since otherwise we can't even - // deep_copy to it. - using data_type = typename src_view_type::non_const_data_type; - // The destination view type if it is not the same memory space - using view_type = Kokkos::View; + + // Check whether it is the same data type + enum { + is_same_data_type = + std::is_same::value + }; + + // Shorthand for both memory space and data type check + enum { + is_same = is_same_memspace && is_same_data_type + }; + + // If it is the same memory_space and data_type return the existsing view_type + // This will also keep the unmanaged trait if necessary + using view_type = + std::conditional_t; }; template @@ -3470,232 +3496,126 @@ void check_view_ctor_args_create_mirror() { "not explicitly allow padding!"); } -template -inline std::enable_if_t::has_memory_space, - typename Kokkos::View::HostMirror> -create_mirror(const Kokkos::View& src, - const Impl::ViewCtorProp& arg_prop) { - using src_type = View; - using dst_type = typename src_type::HostMirror; - - check_view_ctor_args_create_mirror(); +template ::specialize>::value>> +inline auto create_mirror(const Kokkos::View& src, + const Impl::ViewCtorProp& arg_prop) { - auto prop_copy = Impl::with_properties_if_unset( - arg_prop, std::string(src.label()).append("_mirror")); + // get desired space + using space_type = std::conditional_t::has_memory_space, + typename Impl::ViewCtorProp::memory_space, + DefaultHostExecutionSpace::memory_space>; - return dst_type(prop_copy, src.layout()); -} + using mirror_view_type = typename Impl::MirrorViewType; -// Create a mirror in a new space (specialization for different space) -template ::has_memory_space>> -auto create_mirror(const Kokkos::View& src, - const Impl::ViewCtorProp& arg_prop) { check_view_ctor_args_create_mirror(); + // append label name with "_mirror" auto prop_copy = Impl::with_properties_if_unset( arg_prop, std::string(src.label()).append("_mirror")); - using alloc_prop = decltype(prop_copy); - return typename Impl::MirrorType::view_type(prop_copy, src.layout()); -} + return typename mirror_view_type::dest_view_type(prop_copy, src.layout()); + } } // namespace Impl +// view template -std::enable_if_t::specialize>::value, - typename Kokkos::View::HostMirror> -create_mirror(Kokkos::View const& v) { +auto create_mirror(Kokkos::View const& v) { return Impl::create_mirror(v, Impl::ViewCtorProp<>{}); } +// view and without initializing template -std::enable_if_t::specialize>::value, - typename Kokkos::View::HostMirror> -create_mirror(Kokkos::Impl::WithoutInitializing_t wi, +auto create_mirror(Kokkos::Impl::WithoutInitializing_t wi, Kokkos::View const& v) { return Impl::create_mirror(v, view_alloc(wi)); } -template ::value>> -std::enable_if_t::specialize>::value, - typename Impl::MirrorType::view_type> -create_mirror(Space const&, Kokkos::View const& v) { +// view and space +template ::value>> +auto create_mirror(Space const&, Kokkos::View const& v) { return Impl::create_mirror(v, view_alloc(typename Space::memory_space{})); } +// view, space and without initializing +template ::value>> +auto create_mirror(Kokkos::Impl::WithoutInitializing_t wi, Space const&, + Kokkos::View const& v) { + return Impl::create_mirror(v, view_alloc(typename Space::memory_space{}, wi)); +} + +// view and view constructor properties template ::specialize>::value && - Impl::ViewCtorProp::has_memory_space>> + class = std::enable_if::specialize>::value>> auto create_mirror(Impl::ViewCtorProp const& arg_prop, Kokkos::View const& v) { return Impl::create_mirror(v, arg_prop); } -template -std::enable_if_t< - std::is_void::specialize>::value && - !Impl::ViewCtorProp::has_memory_space, - typename Kokkos::View::HostMirror> -create_mirror(Impl::ViewCtorProp const& arg_prop, - Kokkos::View const& v) { - return Impl::create_mirror(v, arg_prop); -} - -template ::value>> -std::enable_if_t::specialize>::value, - typename Impl::MirrorType::view_type> -create_mirror(Kokkos::Impl::WithoutInitializing_t wi, Space const&, - Kokkos::View const& v) { - return Impl::create_mirror(v, view_alloc(typename Space::memory_space{}, wi)); -} - namespace Impl { template -inline std::enable_if_t< - !Impl::ViewCtorProp::has_memory_space && - (std::is_same< - typename Kokkos::View::memory_space, - typename Kokkos::View::HostMirror::memory_space>::value && - std::is_same< - typename Kokkos::View::data_type, - typename Kokkos::View::HostMirror::data_type>::value), - typename Kokkos::View::HostMirror> -create_mirror_view(const Kokkos::View& src, - const Impl::ViewCtorProp&) { - check_view_ctor_args_create_mirror(); - return src; -} +inline auto create_mirror_view(const Kokkos::View& src, + const Impl::ViewCtorProp& arg_prop) { -template -inline std::enable_if_t< - !Impl::ViewCtorProp::has_memory_space && - !(std::is_same::memory_space, - typename Kokkos::View< - T, P...>::HostMirror::memory_space>::value && - std::is_same< - typename Kokkos::View::data_type, - typename Kokkos::View::HostMirror::data_type>::value), - typename Kokkos::View::HostMirror> -create_mirror_view(const Kokkos::View& src, - const Impl::ViewCtorProp& arg_prop) { - return Kokkos::Impl::create_mirror(src, arg_prop); -} - -// Create a mirror view in a new space (specialization for same space) -template ::has_memory_space>> -std::enable_if_t::memory_space, - T, P...>::is_same_memspace, - typename Impl::MirrorViewType< - typename Impl::ViewCtorProp::memory_space, - T, P...>::view_type> -create_mirror_view(const Kokkos::View& src, - const Impl::ViewCtorProp&) { - check_view_ctor_args_create_mirror(); - return src; -} + // get desired space + using space_type = std::conditional_t::has_memory_space, + typename Impl::ViewCtorProp::memory_space, + DefaultHostExecutionSpace::memory_space>; -// Create a mirror view in a new space (specialization for different space) -template ::has_memory_space>> -std::enable_if_t::memory_space, - T, P...>::is_same_memspace, - typename Impl::MirrorViewType< - typename Impl::ViewCtorProp::memory_space, - T, P...>::view_type> -create_mirror_view(const Kokkos::View& src, - const Impl::ViewCtorProp& arg_prop) { - return Kokkos::Impl::create_mirror(src, arg_prop); -} -} // namespace Impl + using mirror_view_type = typename Impl::MirrorViewType; -template -std::enable_if_t< - std::is_same< - typename Kokkos::View::memory_space, - typename Kokkos::View::HostMirror::memory_space>::value && - std::is_same< - typename Kokkos::View::data_type, - typename Kokkos::View::HostMirror::data_type>::value, - typename Kokkos::View::HostMirror> -create_mirror_view(const Kokkos::View& src) { - return src; + if constexpr (mirror_view_type::is_same) { + // shallow copy if src and dest both spaces and data types are the same + check_view_ctor_args_create_mirror(); + return src; + } else { + // create mirror if src and dest spaces are different + return Kokkos::Impl::create_mirror(src, arg_prop); + } } +} // namespace Impl +// view template -std::enable_if_t< - !(std::is_same< - typename Kokkos::View::memory_space, - typename Kokkos::View::HostMirror::memory_space>::value && - std::is_same< - typename Kokkos::View::data_type, - typename Kokkos::View::HostMirror::data_type>::value), - typename Kokkos::View::HostMirror> -create_mirror_view(const Kokkos::View& src) { - return Kokkos::create_mirror(src); +auto create_mirror_view(const Kokkos::View& src) { + return Impl::create_mirror_view(src, Impl::ViewCtorProp<>{}); } +// view and without initializing template -typename Kokkos::View::HostMirror create_mirror_view( - Kokkos::Impl::WithoutInitializing_t wi, Kokkos::View const& v) { - return Impl::create_mirror_view(v, view_alloc(wi)); +auto create_mirror_view( + Kokkos::Impl::WithoutInitializing_t wi, Kokkos::View const& src) { + return Impl::create_mirror_view(src, view_alloc(wi)); } -// FIXME_C++17 Improve SFINAE here. -template ::value>> -typename Impl::MirrorViewType::view_type create_mirror_view( - const Space&, const Kokkos::View& src, - std::enable_if_t::is_same_memspace>* = - nullptr) { - return src; +// view and space +template ::value>> +auto create_mirror_view( + const Space&, const Kokkos::View& src) { + return Impl::create_mirror_view(src, view_alloc(typename Space::memory_space{})); } -// FIXME_C++17 Improve SFINAE here. -template ::value>> -typename Impl::MirrorViewType::view_type create_mirror_view( - const Space& space, const Kokkos::View& src, - std::enable_if_t::is_same_memspace>* = - nullptr) { - return Kokkos::create_mirror(space, src); -} - -template ::value>> -typename Impl::MirrorViewType::view_type create_mirror_view( +// view, space and without initializing +template ::value>> +auto create_mirror_view( Kokkos::Impl::WithoutInitializing_t wi, Space const&, - Kokkos::View const& v) { + Kokkos::View const& src) { return Impl::create_mirror_view( - v, view_alloc(typename Space::memory_space{}, wi)); + src, view_alloc(typename Space::memory_space{}, wi)); } +// view and view constructor properties template auto create_mirror_view(const Impl::ViewCtorProp& arg_prop, const Kokkos::View& v) { return Impl::create_mirror_view(v, arg_prop); } -template -auto create_mirror_view_and_copy( - const Impl::ViewCtorProp&, - const Kokkos::View& src, - std::enable_if_t< - std::is_void::specialize>::value && - Impl::MirrorViewType< - typename Impl::ViewCtorProp::memory_space, T, - P...>::is_same_memspace>* = nullptr) { +template +void check_view_ctor_args_create_mirror_and_copy() { using alloc_prop_input = Impl::ViewCtorProp; + static_assert( alloc_prop_input::has_memory_space, "The view constructor arguments passed to " @@ -3708,66 +3628,56 @@ auto create_mirror_view_and_copy( "The view constructor arguments passed to " "Kokkos::create_mirror_view_and_copy must " "not explicitly allow padding!"); - - // same behavior as deep_copy(src, src) - if (!alloc_prop_input::has_execution_space) - fence( - "Kokkos::create_mirror_view_and_copy: fence before returning src view"); - return src; } -template +template ::specialize>::value>> auto create_mirror_view_and_copy( const Impl::ViewCtorProp& arg_prop, - const Kokkos::View& src, - std::enable_if_t< - std::is_void::specialize>::value && - !Impl::MirrorViewType< - typename Impl::ViewCtorProp::memory_space, T, - P...>::is_same_memspace>* = nullptr) { - using alloc_prop_input = Impl::ViewCtorProp; - static_assert( - alloc_prop_input::has_memory_space, - "The view constructor arguments passed to " - "Kokkos::create_mirror_view_and_copy must include a memory space!"); - static_assert(!alloc_prop_input::has_pointer, - "The view constructor arguments passed to " - "Kokkos::create_mirror_view_and_copy must " - "not include a pointer!"); - static_assert(!alloc_prop_input::allow_padding, - "The view constructor arguments passed to " - "Kokkos::create_mirror_view_and_copy must " - "not explicitly allow padding!"); - using Space = typename alloc_prop_input::memory_space; - using Mirror = typename Impl::MirrorViewType::view_type; - - auto arg_prop_copy = Impl::with_properties_if_unset( - arg_prop, std::string{}, WithoutInitializing, - typename Space::execution_space{}); - - std::string& label = Impl::get_property(arg_prop_copy); - if (label.empty()) label = src.label(); - auto mirror = typename Mirror::non_const_type{arg_prop_copy, src.layout()}; - if constexpr (alloc_prop_input::has_execution_space) { - deep_copy(Impl::get_property(arg_prop_copy), - mirror, src); - } else - deep_copy(mirror, src); - return mirror; -} + const Kokkos::View& src) { + + using alloc_prop_input = Impl::ViewCtorProp; + check_view_ctor_args_create_mirror_and_copy(); + + // get desired space + using space_type = std::conditional_t; + + using mirror_view_type = typename Impl::MirrorViewType; + + if constexpr(mirror_view_type::is_same){ + // same behavior as deep_copy(src, src) + if constexpr (!alloc_prop_input::has_execution_space) + fence( + "Kokkos::create_mirror_view_and_copy: fence before returning src view"); + + return src; + } else { + using nonconst_mirror = typename mirror_view_type::dest_view_type; + auto arg_prop_copy = Impl::with_properties_if_unset( + arg_prop, std::string{}, WithoutInitializing, + typename space_type::execution_space{}); + + std::string& label = Impl::get_property(arg_prop_copy); + if (label.empty()) label = src.label(); + + auto mirror = nonconst_mirror{arg_prop_copy, src.layout()}; + deep_copy(Impl::get_property(arg_prop_copy), mirror, src); + return mirror; + } + } // Previously when using auto here, the intel compiler 19.3 would // sometimes not create a symbol, guessing that it somehow is a combination // of auto and just forwarding arguments (see issue #5196) template ::value>> + typename Enable = std::enable_if_t::value>, + class = std::enable_if_t::specialize>::value>> typename Impl::MirrorViewType::view_type create_mirror_view_and_copy( const Space&, const Kokkos::View& src, - std::string const& name = "", - std::enable_if_t< - std::is_void::specialize>::value>* = - nullptr) { + std::string const& name = "") { return create_mirror_view_and_copy( Kokkos::view_alloc(typename Space::memory_space{}, name), src); }