Project

General

Profile

Task #2221

Updated by Roland Schulz about 3 years ago

To further avoid using the preprocessor for SIMD function, we need to be able to use enable_if on functions which should only work for certain SIMD features. Because two-phase lookup will give an error on non-dependent names and because enable_if only works if it depends on the SIMD template argument, I suggest to have the SIMD functions/types in a wrapper class (one for each implementation).

The resulting code (this is simplified code, e.g. the load function is missing its argument) would look similar to:
<pre>
#include <cstdio>
#include <type_traits>

struct AVXSimd { //defined in //one for each implementation
using haveFloat = std::true_type; //why GMX_SIMD_HAVE_FLOAT not HAS?
struct Real { Real operator+(Real) {return Real();} };
static Real load() {return Real();}
};
struct NoSimd { //This is different from scalar which would have its own
using haveFloat = std::false_type;
};

using DefaultSimd=AVXSimd; //This would be set based on GMX_SIMD
//using DefaultSimd=NoSimd;

template<typename T=DefaultSimd>
typename std::enable_if<T::haveFloat::value>::type f() {
printf("simd\n");
using Real = typename T::Real; //avoiding T::Real x; //not nice that typename T:: on each one
Real x;
is needed here
auto y = T::load(); //freestanding functions require the T:: prefix
x+y;
}

template<typename T=DefaultSimd>
typename std::enable_if<!T::haveFloat::value>::type f() {
printf("fallback\n");
}

int main() {
f();
return 1;
}
</pre>

The wrapper class could be made the only interface used by all functions or it could be a wrapper around the existing freestanding functions/types only used by code wanting to use templates with enable_if.

The advantages of enable_if over #if are:
- Both code paths are checked for syntax errors.
- One can execute a function with a different SIMD implementation than the default.
- Potentially better error messages when getting the conditional logic wrong (e.g. #if errors are confusing when nesting of them is wrong)

Disadvantages:
- possible slower compile time.
- maybe harder to read for some people.
- typename keyword is required for simd types

Should we have those wrapper classes and if so as the only interface or as an optional interface?

Back