//@HEADER // ************************************************************************ // // Kokkos v. 4.0 // Copyright (2022) National Technology & Engineering // Solutions of Sandia, LLC (NTESS). // // Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions. // See https://kokkos.org/LICENSE for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //@HEADER #ifndef KOKKOS_EXPERIMENTAL_IMPL_VIEW_CTOR_PROP_HPP #define KOKKOS_EXPERIMENTAL_IMPL_VIEW_CTOR_PROP_HPP //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- namespace Kokkos { namespace Impl { struct WithoutInitializing_t {}; struct AllowPadding_t {}; template struct is_view_ctor_property : public std::false_type {}; template <> struct is_view_ctor_property : public std::true_type {}; template <> struct is_view_ctor_property : public std::true_type {}; //---------------------------------------------------------------------------- /**\brief Whether a type can be used for a view label */ template struct is_view_label : public std::false_type {}; template <> struct is_view_label : public std::true_type {}; template struct is_view_label : public std::true_type {}; template struct is_view_label : public std::true_type {}; //---------------------------------------------------------------------------- template struct ViewCtorProp; // Forward declare template struct CommonViewAllocProp; /* Dummy to allow for empty ViewCtorProp object */ template <> struct ViewCtorProp {}; /* Common value_type stored as ViewCtorProp */ template struct ViewCtorProp> { ViewCtorProp() = default; ViewCtorProp(const ViewCtorProp &) = default; ViewCtorProp &operator=(const ViewCtorProp &) = default; using type = CommonViewAllocProp; KOKKOS_FUNCTION ViewCtorProp(const type &arg) : value(arg) {} KOKKOS_FUNCTION ViewCtorProp(type &&arg) : value(arg) {} type value; }; /* Property flags have constexpr value */ template struct ViewCtorProp< std::enable_if_t::value || std::is_same::value>, P> { ViewCtorProp() = default; ViewCtorProp(const ViewCtorProp &) = default; ViewCtorProp &operator=(const ViewCtorProp &) = default; using type = P; ViewCtorProp(const type &) {} type value = type(); }; /* Map input label type to std::string */ template struct ViewCtorProp::value>, Label> { ViewCtorProp() = default; ViewCtorProp(const ViewCtorProp &) = default; ViewCtorProp &operator=(const ViewCtorProp &) = default; using type = std::string; ViewCtorProp(const type &arg) : value(arg) {} ViewCtorProp(type &&arg) : value(arg) {} type value; }; template struct ViewCtorProp::value || Kokkos::is_execution_space::value>, Space> { ViewCtorProp() = default; ViewCtorProp(const ViewCtorProp &) = default; ViewCtorProp &operator=(const ViewCtorProp &) = default; using type = Space; ViewCtorProp(const type &arg) : value(arg) {} type value; }; template struct ViewCtorProp { ViewCtorProp() = default; ViewCtorProp(const ViewCtorProp &) = default; ViewCtorProp &operator=(const ViewCtorProp &) = default; using type = T *; KOKKOS_FUNCTION ViewCtorProp(const type arg) : value(arg) {} type value; }; // For some reason I don't understand I needed this specialization explicitly // for NVCC/MSVC template struct ViewCtorProp : public ViewCtorProp { static constexpr bool has_memory_space = false; static constexpr bool has_execution_space = false; static constexpr bool has_pointer = true; static constexpr bool has_label = false; static constexpr bool allow_padding = false; static constexpr bool initialize = true; using memory_space = void; using execution_space = void; using pointer_type = T *; KOKKOS_FUNCTION ViewCtorProp(const pointer_type arg) : ViewCtorProp(arg) {} }; // If we use `ViewCtorProp` and `ViewCtorProp...` directly // in the parameter lists and base class initializers, respectively, as far as // we can tell MSVC 16.5.5+CUDA 10.2 thinks that `ViewCtorProp` refers to the // current instantiation, not the template itself, and gets all kinds of // confused. To work around this, we just use a couple of alias templates that // amount to the same thing. template using view_ctor_prop_args = ViewCtorProp; template using view_ctor_prop_base = ViewCtorProp; template struct ViewCtorProp : public ViewCtorProp... { private: using var_memory_space = Kokkos::Impl::has_condition; using var_execution_space = Kokkos::Impl::has_condition; struct VOIDDUMMY {}; using var_pointer = Kokkos::Impl::has_condition; public: /* Flags for the common properties */ static constexpr bool has_memory_space = var_memory_space::value; static constexpr bool has_execution_space = var_execution_space::value; static constexpr bool has_pointer = var_pointer::value; static constexpr bool has_label = Kokkos::Impl::has_type::value; static constexpr bool allow_padding = Kokkos::Impl::has_type::value; static constexpr bool initialize = !Kokkos::Impl::has_type::value; using memory_space = typename var_memory_space::type; using execution_space = typename var_execution_space::type; using pointer_type = typename var_pointer::type; /* Copy from a matching argument list. * Requires std::is_same< P , ViewCtorProp< void , Args >::value ... */ template inline ViewCtorProp(Args const &... args) : ViewCtorProp(args)... {} template KOKKOS_FUNCTION ViewCtorProp(pointer_type arg0, Args const &... args) : ViewCtorProp(arg0), ViewCtorProp::type>(args)... {} /* Copy from a matching property subset */ KOKKOS_FUNCTION ViewCtorProp(pointer_type arg0) : ViewCtorProp(arg0) {} // If we use `ViewCtorProp` and `ViewCtorProp...` here // directly, MSVC 16.5.5+CUDA 10.2 appears to think that `ViewCtorProp` refers // to the current instantiation, not the template itself, and gets all kinds // of confused. To work around this, we just use a couple of alias templates // that amount to the same thing. template ViewCtorProp(view_ctor_prop_args const &arg) : view_ctor_prop_base( static_cast const &>(arg))... { // Suppress an unused argument warning that (at least at one point) would // show up if sizeof...(Args) == 0 (void)arg; } }; #if !defined(KOKKOS_COMPILER_MSVC) || !defined(KOKKOS_COMPILER_NVCC) template auto with_properties_if_unset(const ViewCtorProp &view_ctor_prop) { return view_ctor_prop; } template auto with_properties_if_unset(const ViewCtorProp &view_ctor_prop, [[maybe_unused]] const Property &property, const Properties &... properties) { if constexpr ((is_execution_space::value && !ViewCtorProp::has_execution_space) || (is_memory_space::value && !ViewCtorProp::has_memory_space) || (is_view_label::value && !ViewCtorProp::has_label) || (std::is_same_v && ViewCtorProp::initialize)) { using NewViewCtorProp = ViewCtorProp; NewViewCtorProp new_view_ctor_prop(view_ctor_prop); static_cast &>(new_view_ctor_prop).value = property; return with_properties_if_unset(new_view_ctor_prop, properties...); } else return with_properties_if_unset(view_ctor_prop, properties...); // A workaround placed to prevent spurious "missing return statement at the // end of non-void function" warnings from CUDA builds (issue #5470). Because // KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK removes [[noreturn]] attribute from // cuda_abort(), an unreachable while(true); is placed as a fallback method #if (defined(KOKKOS_COMPILER_NVCC) && (KOKKOS_COMPILER_NVCC < 1150)) || \ (defined(KOKKOS_COMPILER_INTEL) && (KOKKOS_COMPILER_INTEL <= 2100)) Kokkos::abort( "Prevents an incorrect warning: missing return statement at end of " "non-void function"); #ifdef KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK while (true) ; #endif #endif } #else template struct WithPropertiesIfUnset; template struct WithPropertiesIfUnset { static constexpr auto apply_prop(const ViewCtorP &view_ctor_prop) { return view_ctor_prop; } }; template struct WithPropertiesIfUnset, Property, Properties...> { static constexpr auto apply_prop(const ViewCtorProp &view_ctor_prop, const Property &prop, const Properties &... properties) { if constexpr ((is_execution_space::value && !ViewCtorProp::has_execution_space) || (is_memory_space::value && !ViewCtorProp::has_memory_space) || (is_view_label::value && !ViewCtorProp::has_label) || (std::is_same_v && ViewCtorProp::initialize)) { using NewViewCtorProp = ViewCtorProp; NewViewCtorProp new_view_ctor_prop(view_ctor_prop); static_cast &>(new_view_ctor_prop).value = prop; return WithPropertiesIfUnset::apply_prop( new_view_ctor_prop, properties...); } else return WithPropertiesIfUnset, Properties...>::apply_prop(view_ctor_prop, properties...); } }; template auto with_properties_if_unset(const ViewCtorProp &view_ctor_prop, const Properties &... properties) { return WithPropertiesIfUnset, Properties...>::apply_prop( view_ctor_prop, properties...); } #endif struct ExecutionSpaceTag {}; struct MemorySpaceTag {}; struct LabelTag {}; struct PointerTag {}; template KOKKOS_FUNCTION const auto &get_property( const ViewCtorProp &view_ctor_prop) { if constexpr (std::is_same_v) { static_assert(ViewCtorProp::has_execution_space); using execution_space_type = typename ViewCtorProp::execution_space; return static_cast &>( view_ctor_prop) .value; } else if constexpr (std::is_same_v) { static_assert(ViewCtorProp::has_memory_space); using memory_space_type = typename ViewCtorProp::memory_space; return static_cast &>( view_ctor_prop) .value; } else if constexpr (std::is_same_v) { static_assert(ViewCtorProp::has_label); return static_cast &>(view_ctor_prop) .value; } else if constexpr (std::is_same_v) { static_assert(ViewCtorProp::has_pointer); using pointer_type = typename ViewCtorProp::pointer_type; return static_cast &>(view_ctor_prop) .value; } else { static_assert(std::is_same_v, "Invalid property tag!"); return view_ctor_prop; } // A workaround placed to prevent spurious "missing return statement at the // end of non-void function" warnings from CUDA builds (issue #5470). Because // KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK removes [[noreturn]] attribute from // cuda_abort(), an unreachable while(true); is placed as a fallback method #if (defined(KOKKOS_COMPILER_NVCC) && (KOKKOS_COMPILER_NVCC < 1150)) || \ (defined(KOKKOS_COMPILER_INTEL) && (KOKKOS_COMPILER_INTEL <= 2100)) Kokkos::abort( "Prevents an incorrect warning: missing return statement at end of " "non-void function"); #ifdef KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK while (true) ; #endif #endif } #if defined(KOKKOS_COMPILER_NVCC) && (KOKKOS_COMPILER_NVCC < 1150) // pragma pop is getting a warning from the underlying GCC // for unknown pragma if -pedantic is used #ifdef __CUDA_ARCH__ #pragma pop #endif #endif #ifdef KOKKOS_IMPL_INTEL_BOGUS_MISSING_RETURN_STATEMENT_AT_END_OF_NON_VOID_FUNCTION #pragma warning(pop) #undef KOKKOS_IMPL_INTEL_BOGUS_MISSING_RETURN_STATEMENT_AT_END_OF_NON_VOID_FUNCTION #endif template KOKKOS_FUNCTION auto &get_property(ViewCtorProp &view_ctor_prop) { // Avoid code duplication by deferring to the const-qualified overload and // casting the const away from the return type const auto &tmp = get_property( static_cast &>(view_ctor_prop)); return const_cast &>(tmp); } } /* namespace Impl */ } /* namespace Kokkos */ //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- namespace Kokkos { namespace Impl { struct ViewAllocateWithoutInitializingBackwardCompat {}; template <> struct ViewCtorProp {}; // NOTE This specialization is meant to be used as the // ViewAllocateWithoutInitializing alias below. All it does is add a // constructor that takes the label as single argument. template <> struct ViewCtorProp : ViewCtorProp, ViewCtorProp { ViewCtorProp(std::string label) : ViewCtorProp( WithoutInitializing_t(), std::move(label)) {} }; } /* namespace Impl */ using ViewAllocateWithoutInitializing = Impl::ViewCtorProp; } /* namespace Kokkos */ //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- #endif