1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
|
// SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root
// SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception
#ifndef DUNE_COMMON_SIMD_BASE_HH
#define DUNE_COMMON_SIMD_BASE_HH
/** @file
* @brief Basic definitions for SIMD Implementations
* @ingroup SIMDAbstract
*
* This file provides basic definitions and template declarations that are
* used to write SIMD abstraction layers.
*
* This file should never be included by users of the SIMD
* abstraction. Include <dune/common/simd/simd.hh> instead.
*/
/** @defgroup SIMD Vectorization
* @ingroup Common
* @brief Abstractions for using vectorization libraries
*
* This vectorization abstraction targets three kinds of developers:
*
* - Application developers create SIMD types (usually with the help of some
* vectorization library) and pass them to the Dune library. They are
* responsible for a compilation unit, typically a .cc file that is compiled
* into a program or part of a library. Since they create the type, they
* have the knowledge which library abstraction is needed and are
* responsible for including that, as well as making sure the correct
* compiler flags are provided.
*
* - Library developers implement support in Dune for handling SIMD types,
* e.g. by extending some existing class. By using the interfaces provided
* here, they should not have to worry about the exact vectorization library
* being used, or whether a vectorization library is used at all.
*
* - Abstraction developers provide the necessary hooks to make a
* vectorization library known to this interface. They are also responsible
* for documenting for application developers how to meet the prerequisites
* for using the abstraction, e.g. which headers to include and how to add
* the necessary compiler flags.
*/
/** @defgroup SIMDApp Application Developer's Interface
* @ingroup SIMD
* @brief How to request vectorization from Dune
*
* This module describes how to pass vectorized types to Dune classes. It
* lists the supported vectorization libraries and how to include each
* (although it cannot list those libraries where support is not part of the
* dune core).
*/
/** @defgroup SIMDLib Library Developer's Interface
* @ingroup SIMD
* @brief How to support vectorization in Dune classes
*
* This module describes how a Dune library developer can add support for
* vectorization to library facilities.
*/
/** @defgroup SIMDAbstract Abstraction Developer's Interface
* @ingroup SIMD
* @brief How to add support for a new vectorization library
*
* This module describes the interface that you must implement if you want to
* provide an abstraction layer for some vectorization library. To understand
* some of the design choices, have a look at dune/common/simd/DESIGN.md in
* dune-common's source.
*
* Everything an abstraction implementation needs to provide is in namespace
* `Dune::Simd::Overloads`.
*
* An implementation must specialize all the template classes in namespace
* `Overloads` (with the exception of `Overloads::ADLTag`, see below). To
* make it possible for certain specializations not to participate in overload
* resolution, each template class provides a dummy template parameter \c
* SFINAETag that defaults to \c void.
*
* An implementation must overload all functions within namespace `Overloads`
* that are defined deleted. It may overload other functions if the default
* behaviour is not suitable. All functions take a value of type
* `Overloads::ADLTag<priority, true>` as their first argument to enable
* argument-dependent lookup, to be able to prioritize different overloads
* with respect to each other, and to be able to inhibit certain overloads
* from taking part in overload resolution. See the documentation for
* `Overloads::ADLTag` for a detailed explanation.
*
* An abstraction implementation may not specialize `Overloads::ADLTag`, and
* may not introduce new names into namespace `Overloads`.
*/
namespace Dune {
namespace Simd {
//! @brief Namespace for the overloads and specializations that make up a
//! SIMD implementation
/**
* @ingroup SIMDAbstract
*
* This namespace contains three sets of things: the struct ADLTag, which
* is used to look up functions in this namespace using argument-dependet
* lookup, traits classes that must be specialized by abstraction
* implementations, and functions that must/can be overloaded by
* abstraction implementations.
*
* \note Only introduce new names into this namespace to extend the
* interface. This applies in particular to people in the
* "abstraction developer" role; they may meddle in this namespace
* only by providing overloads and/or specializations for existing
* names (and for `ADLTag` even that is prohibited).
*/
namespace Overloads {
//! @addtogroup SIMDAbstract
//! @{
//! Tag used to force late-binding lookup in Dune::Simd::Overloads
/**
* This tag is used by functions in \c Dune::Simd to make
* argument-dependent lookups (ADL) for functions in \c
* Dune::Simd::Overloads. The property of ADL that is used here is that
* it binds the names of functions late, i.e. at the time of
* instantiation, while all other lookups bind early, i.e. at the time
* when the function call is parsed. Using late binding enables a
* function \c foo() to find a functions \c Overloads::foo() that has
* been declared only after \c foo() itself has been defined:
*
* \code
* template<class V>
* void foo(V v)
* {
* foo(Overloads::ADLTag<6>{}, v);
* }
*
* struct MyType {};
* namespace Overloads {
* void foo(ADLTag<4>, MyType v);
* }
* \endcode
*
* \note It is generally an error to declare a function with an ADLTag
* argument outside of namespace Simd::Overloads. An exception
* would be an abstraction implementation that declares all its
* implementation functions in its own implementation namespace,
* and then pulls them into the namespace Overloads by way of \c
* using.
*
* `ADLTag<i>` derives from `ADLTag<i-1>`. Thus it is possible to
* prioritize overloads by choosing an appropriate \c i. The following
* values for \c i are predefined:
* - `i==0,1`: these are reserved for the defaults.
* - `i==2,3`: these are reserved for the implementation for standard
* types.
* - `i==5,6`: these should normally be used by other implementations
*
* The lower priority should be used by default. The higher priority
* can be used by an implementation to resolve ambiguities, e.g. between
* an overload with a by-value argument and an overload with an
* lvalue-reference argument.
*
* The following priorities should not normally be used. However, they
* may sometimes be necessary:
* - \c i==4: override standard implementation, but prefer other
* implementations
* - \c i==7: try to override other implementations
*
* \c i==7 is the highest supported priority.
*
* The second (bool) template argument is to make writing abstraction
* implementations that use SFINAE to remove (some of) their functions
* from the overload set more concise. \c ADLTag<i,false> is not
* defined, so instead of
* \code
* std::enable_if_t<cond, ADLTag<4> >
* \endcode
* you may write the equivalent
* \code
* ADLTag<4, cond>
* \endcode
*/
template<unsigned i, bool = true>
struct ADLTag;
template<unsigned i>
struct ADLTag<i> : ADLTag<i-1> {};
template<>
struct ADLTag<0> {};
//! should have a member type \c type
/**
* Implements `Simd::Scalar`. `V` will never have cv or reference
* qualifiers, no need to strip those.
*/
template<class V, class SFINAETag = void>
struct ScalarType;
//! should have a member type \c type
/**
* Implements `Simd::Rebind`. `V` and `S` will never have cv or
* reference qualifiers, no need to strip those.
*/
template<class S, class V, class SFINAETag = void>
struct RebindType;
//! should be derived from a `Dune::index_constant`
/**
* Implements `Simd::lanes()`. `V` will never have cv or reference
* qualifiers, no need to strip those.
*/
template<class V, class SFINAETag = void>
struct LaneCount;
//! @} Group SIMDAbstract
} // namespace Overloads
} // namespace Simd
} // namespace Dune
#endif // DUNE_COMMON_SIMD_BASE_HH
|