K. G. K. G. - 1 month ago 13
C++ Question

Write one generic kernel and map it to different ISAs

UPDATE: I guess the question can be summarized as: "Is there a modern C++ approach that is equivalent to polymorphic function-like macros?"




I wonder if it is possible to program in C++ to write one kernel with the abstract operations, and automatically produce ISA-specific codes. For example, a generic kernel can be:

RET_TYPE kernel(IN_TYPE a, IN_TYPE b)
{
RET_TYPE res = ADD(a, b);
return res;
}


And the kernel can be transformed into both a scalar version:

float kernel(float a, float b)
{
float res = a + b;
return res;
}


and a vectorized version:

__m128 kernel(__m128 a, __m128 b)
{
__m128 res = _mm_add_ps(a, b);
return res;
}


In reality, the generic kernels would be much more complex. The genericity in the types can be handled by template parameters. But the genericity of the instructions got me stuck.

Usually, this kind of problem is addressed via Code Generation, where you write the program in some Intermediate Representation (IR) and then translate the IR expression into various target language.

However, I have to do it within pure and modern C++, meaning no C macros. I wonder if it's achievable by cleverly exploiting Generic Programming, Template Metaprogramming or OOP. Please help if you have some pointers!

Answer

Generally it's achievable with templates and type traits:

template <typename T>
T kernel(T a, T b)
{
     return MathTraits<T>::add (a, b);
}
template <typename T>
class MathTraits 
{
}
// specialization for float
template <>
class MathTraits <float>
{
     float add(float a, float b)
     {
          return a+b;
     }
}
// specialization of MathTraits for __m128 etc.

However, this approach may fail when you may want to treat the same type differently in different situations. But that's general limit of overloading...

With the example given it's actually possible to directly specialize the function but the way described is more common as it's more clear and reusable.

Comments