diff --git a/cmake/modules/AddVcFlags.cmake b/cmake/modules/AddVcFlags.cmake new file mode 100644 index 0000000000000000000000000000000000000000..0ca689adbb221979cae908a65c28548995753885 --- /dev/null +++ b/cmake/modules/AddVcFlags.cmake @@ -0,0 +1,31 @@ +# Defines the functions to use Vc +# +# Vc is a library for high-level Vectorization support in C++ +# see https://github.com/VcDevel/Vc +# +# .. cmake_function:: add_dune_vc_flags +# +# .. cmake_param:: targets +# :positional: +# :single: +# :required: +# +# A list of targets to use VC with. +# + +function(add_dune_vc_flags _targets) + if(Vc_FOUND) + foreach(_target ${_targets}) + target_link_libraries(${_target} ${Vc_LIBRARIES}) + target_compile_options(${_target} PUBLIC ${Vc_ALL_FLAGS}) + target_include_directories(${_target} SYSTEM PUBLIC ${Vc_INCLUDE_DIR}) + endforeach(_target ${_targets}) + endif(Vc_FOUND) +endfunction(add_dune_vc_flags) + +if(Vc_FOUND) + dune_register_package_flags(COMPILE_OPTIONS "${Vc_ALL_FLAGS}" + LIBRARIES "${Vc_LIBRARIES}" + INCLUDE_DIRS "${Vc_INCLUDE_DIR}") +endif(Vc_FOUND) +set(HAVE_VC ${Vc_FOUND}) diff --git a/cmake/modules/CMakeLists.txt b/cmake/modules/CMakeLists.txt index 9d0812e0ad4098d54eed1334448805929517fe0c..e8297679e3d13b779f78c05cf61a9abd0b9aafbd 100644 --- a/cmake/modules/CMakeLists.txt +++ b/cmake/modules/CMakeLists.txt @@ -5,6 +5,7 @@ install(FILES AddPTScotchFlags.cmake AddSuiteSparseFlags.cmake AddUMFPackFlags.cmake + AddVcFlags.cmake CheckCXXFeatures.cmake CheckForPthreads.c CMakeBuiltinFunctionsDocumentation.cmake diff --git a/cmake/modules/DuneCommonMacros.cmake b/cmake/modules/DuneCommonMacros.cmake index 6faa54a8952542da142784417e27b68a61db99e6..086f75698df71f2f4e7da7ea4e214cb7049e1311 100644 --- a/cmake/modules/DuneCommonMacros.cmake +++ b/cmake/modules/DuneCommonMacros.cmake @@ -24,3 +24,8 @@ include(AddGMPFlags) find_package(Inkscape) include(UseInkscape) include(FindMProtect) + +# try to find the Vc library +find_package(Vc) +include(AddVcFlags) +set_package_info("Vc" "C++ Vectorization library" "https://github.com/VcDevel/Vc") diff --git a/config.h.cmake b/config.h.cmake index e34d1887c9a4c41a296c82dfc908469cdf95ae4d..6e1fd357d2a8f210f3977e7efa705015869816c9 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -45,6 +45,9 @@ to facilitate activating and deactivating GMP using compile flags. */ #cmakedefine HAVE_GMP ENABLE_GMP +/* Define to 1 if you have the Vc library. */ +#cmakedefine HAVE_VC 1 + /* Define to 1 if you have the symbol mprotect. */ #cmakedefine HAVE_MPROTECT 1 diff --git a/doc/doxygen/modules.txt b/doc/doxygen/modules.txt index 3ff40607650c740d7d585df7f630bfefb63b2266..d70023de3b319c5b974b1d312eff76f5caebb12d 100644 --- a/doc/doxygen/modules.txt +++ b/doc/doxygen/modules.txt @@ -21,6 +21,15 @@ @ingroup Utilities */ +/** + @defgroup RangeUtilities Range Utilities + @brief Utilities for reduction like operations on ranges + + All these reduction operations work for appropriate ranges and scalar values + + @ingroup Utilities +*/ + /** @defgroup StringUtilities String Utilities @brief Utility functions for std::string diff --git a/dune/common/CMakeLists.txt b/dune/common/CMakeLists.txt index deadd0fb578fa8238090ca5efa2488211745d611..5b63b16237c22e8d4f4677d398bb90839d7cf0b4 100644 --- a/dune/common/CMakeLists.txt +++ b/dune/common/CMakeLists.txt @@ -34,6 +34,7 @@ install(FILES boundschecking.hh classname.hh concept.hh + conditional.hh debugallocator.hh debugstream.hh deprecated.hh @@ -82,8 +83,10 @@ install(FILES propertymap.hh promotiontraits.hh proxymemberaccess.hh + rangeutilities.hh reservedvector.hh shared_ptr.hh + simd.hh singleton.hh sllist.hh stdstreams.hh diff --git a/dune/common/conditional.hh b/dune/common/conditional.hh new file mode 100644 index 0000000000000000000000000000000000000000..e4590f6845569ae969b41ef3cc63d395f6ca8cff --- /dev/null +++ b/dune/common/conditional.hh @@ -0,0 +1,33 @@ +#ifndef DUNE_COMMON_CONDITIONAL_HH +#define DUNE_COMMON_CONDITIONAL_HH + +namespace Dune +{ + + /** \brief conditional evaluate + + sometimes call immediate if, evaluates to + + \code + if (b) + return v1; + else + return v2; + \endcode + + In contrast to if-then-else the cond function can also be + evaluated for vector valued SIMD data types, see simd.hh. + + \param b boolean value + \param v1 value of b==true + \param v2 value of b==false + */ + template<typename T1, typename T2> + const T1 cond(bool b, const T1 & v1, const T2 & v2) + { + return (b ? v1 : v2); + } + +} // end namespace Dune + +#endif // DUNE_COMMON_CONDITIONAL_HH diff --git a/dune/common/rangeutilities.hh b/dune/common/rangeutilities.hh new file mode 100644 index 0000000000000000000000000000000000000000..09b44d266e2581f974a7a118118ffa17af902712 --- /dev/null +++ b/dune/common/rangeutilities.hh @@ -0,0 +1,114 @@ +// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- +// vi: set et ts=4 sw=2 sts=2: +#ifndef DUNE_COMMON_RANGE_UTILITIES_HH +#define DUNE_COMMON_RANGE_UTILITIES_HH + +#include <dune/common/typetraits.hh> +#include <utility> +#include <type_traits> +#include <bitset> + +/** + * \file + * \brief Utilities for reduction like operations on ranges + * \author Christian Engwer + */ + +/** + * @addtogroup RangeUtilities + * @{ + */ + +namespace Dune +{ + /** + \brief compute the maximum value over a range + + overloads for scalar values, and ranges exist + */ + template <typename T, + typename std::enable_if<is_range<T>::value, int>::type = 0> + typename T::value_type + max_value(const T & v) { + using std::max; + typename T::value_type m; + for (const auto & e : v) + m = max(e,m); + return m; + }; + + template <typename T, + typename std::enable_if<!is_range<T>::value, int>::type = 0> + const T & max_value(const T & v) { return v; }; + + /** + \brief compute the minimum value over a range + + overloads for scalar values, and ranges exist + */ + template <typename T, + typename std::enable_if<is_range<T>::value, int>::type = 0> + typename T::value_type + min_value(const T & v) { + using std::min; + typename T::value_type m; + for (const auto & e : v) + m = min(e,m); + return m; + }; + + template <typename T, + typename std::enable_if<!is_range<T>::value, int>::type = 0> + T & min_value(const T & v) { return v; }; + + /** + \brief similar to std::bitset<N>::any() return true, if any entries is true + + overloads for scalar values, ranges, and std::bitset<N> exist + */ + template <typename T, + typename std::enable_if<is_range<T>::value, int>::type = 0> + bool any_true(const T & v) { + bool b = false; + for (const auto & e : v) + b = b or bool(e); + return b; + }; + + template <typename T, + typename std::enable_if<!is_range<T>::value, int>::type = 0> + bool any_true(const T & v) { return v; }; + + template<std::size_t N> + bool any_true(const std::bitset<N> & b) + { + return b.any(); + } + + /** + \brief similar to std::bitset<N>::all() return true, if any entries is true + + overloads for scalar values, ranges, and std::bitset<N> exist + */ + template <typename T, + typename std::enable_if<is_range<T>::value, int>::type = 0> + bool all_true(const T & v) { + bool b = true; + for (const auto & e : v) + b = b and bool(e); + return b; + }; + + template <typename T, + typename std::enable_if<!is_range<T>::value, int>::type = 0> + bool all_true(const T & v) { return v; }; + + template<std::size_t N> + bool all_true(const std::bitset<N> & b) + { + return b.all(); + } + +} + +#endif // DUNE_COMMON_RANGE_UTILITIES_HH diff --git a/dune/common/simd.hh b/dune/common/simd.hh new file mode 100644 index 0000000000000000000000000000000000000000..f266559476473566fcbe15f5afc9996d84a93eac --- /dev/null +++ b/dune/common/simd.hh @@ -0,0 +1,133 @@ +#ifndef DUNE_COMMON_SIMD_HH +#define DUNE_COMMON_SIMD_HH + +/** + \file Abstractions for support of dedicated SIMD data types + + Libraries like Vc (https://github.com/VcDevel/Vc) add high-level + data types for SIMD (or vectorization) support in C++. Most of + these operations mimic the behavior of a numerical data type. Some + boolean operations can not be implemented in a compatible way to + trivial data types. + + This header contains additional abstractions to help writing code + that works with trivial numericaldata types (like double) and Vc + vectorization data types. + + See also the conditional.hh and range_utils.hh headers. + */ + +#include <dune/common/rangeutilities.hh> +#include <dune/common/conditional.hh> +#if HAVE_VC +#include <Vc/Vc> +#endif + +namespace Dune +{ + + template<typename T> + struct SimdScalarTypeTraits + { + using type = T; + }; + + template<typename T> + using SimdScalar = typename SimdScalarTypeTraits<T>::type; + +#if HAVE_VC + /* + Add Vc specializations for the SimdScalarTypeTraits trais class + */ + template<typename T, typename A> + struct SimdScalarTypeTraits< Vc::Vector<T,A> > + { + using type = T; + }; + + template<typename T, std::size_t N, typename V, std::size_t M> + struct SimdScalarTypeTraits< Vc::SimdArray<T,N,V,M> > + { + using type = T; + }; +#endif // HAVE_VC + +#if HAVE_VC + /* + Add Vc specializations for cond(), see conditional.hh + */ + template<typename T, typename A> + Vc::Vector<T,A> cond(const Vc::Mask<T,A> & b, + const Vc::Vector<T,A> & v1, + const Vc::Vector<T,A> & v2) + { + return std::move(Vc::iif(b, v1, v2)); + } + + template<typename T, std::size_t N, typename V, std::size_t M> + Vc::SimdArray<T,N,V,M> cond(const typename Vc::SimdArray<T,N,V,M>::mask_type & b, + const Vc::SimdArray<T,N,V,M> & v1, + const Vc::SimdArray<T,N,V,M> & v2) + { + return std::move(Vc::iif(b, v1, v2)); + } +#endif // HAVE_VC + +#if HAVE_VC + /* + Add Vc specializations for several boolean operations, see rangeutitlities.hh: + + max_value, min_value, any_true, all_true + */ + template<typename T, typename A> + T max_value(const Vc::Vector<T,A> & v) + { + return v.max(); + } + + template<typename T, std::size_t N, typename V, std::size_t M> + double max_value(const Vc::SimdArray<T,N,V,M> & v) + { + return v.max(); + } + + template<typename T, typename A> + T min_value(const Vc::Vector<T,A> & v) + { + return v.min(); + } + + template<typename T, std::size_t N, typename V, std::size_t M> + double min_value(const Vc::SimdArray<T,N,V,M> & v) + { + return v.min(); + } + + template<typename T, typename A> + bool any_true(const Vc::Mask<T,A> & v) + { + return Vc::any_of(v); + } + + template<typename T, std::size_t N, typename V, std::size_t M> + bool any_true(const Vc::SimdMaskArray<T,N,V,M> & v) + { + return Vc::any_of(v); + } + + template<typename T, typename A> + bool all_true(const Vc::Mask<T,A> & v) + { + return Vc::all_of(v); + } + + template<typename T, std::size_t N, typename V, std::size_t M> + bool all_true(const Vc::SimdMaskArray<T,N,V,M> & v) + { + return Vc::all_of(v); + } +#endif // HAVE_VC + +} // end namespace Dune + +#endif // DUNE_COMMON_SIMD_HH diff --git a/dune/common/typetraits.hh b/dune/common/typetraits.hh index cbe30af9f945597860d83e8eafb827fa5c4130b3..10f19e8814a9aeacd3966e48cf0c4a3c595078f7 100644 --- a/dune/common/typetraits.hh +++ b/dune/common/typetraits.hh @@ -395,6 +395,25 @@ namespace Dune #endif // defined(DOXYGEN) or HAVE_IS_INDEXABLE_SUPPORT + /** + typetrait to check that a class has begin() and end() members + */ + // default version, gets picked if SFINAE fails + template<typename T, typename = void, typename = void> + struct is_range + : public std::false_type + {}; + +#ifndef DOXYGEN + // version for types with begin() and end() + template<typename T> + struct is_range<T, + decltype(std::declval<T>().begin()), + decltype(std::declval<T>().end())> + : public std::true_type + {}; +#endif + namespace detail { ///