在我的公司,我正致力于为一些热门代码提供更快的SSE路径。我使用内在的方法来保持C ++并且真正显示出令人印象深刻的结果。
所有代码只需要处理float
和double
,因此我创建了一个模板化的SSE操作类,我专门为它们编写。我真正不喜欢的是这两个类看起来几乎相同,除了数字类型(float
/ double
),使用的SSE类型(__m128
/ {{1 }}和intrisics后缀(__m128d
/ _ps
)如下:
_pd
和
template<>
struct SseOperations<float> : public Sse<float>
{
typedef __m128 vector;
vector load(float const * const from) const
{
return _mm_loadu_ps(from);
}
vector add(vector const & a, vector const & b) const
{
return _mm_add_ps(a, b);
}
// etc.
};
由于内在的后缀不同,我不知道如何使用模板魔术来统一这一点。
然后我想到了宏的template<>
struct SseOperations<double> : public Sse<double>
{
typedef __m128d vector;
vector load(double const * const from) const
{
return _mm_loadu_pd(from);
}
vector add(vector const & a, vector const & b) const
{
return _mm_add_pd(a, b);
}
// etc.
};
能力,这将有助于实现这一目的。所以我设法将完整的专用类放入一个宏,我可以用它来生成两个类:
##
我知道宏是邪恶的,但至少在这种情况下,我没有看到任何典型的危险,它完成了工作。
现在困扰我的是第二和第三个宏参数是多余的;它们可以从第一个推断出来,只是我完全不知道如何。 SSE_OPERATIONS(float, __m128, _ps);
SSE_OPERATIONS(double, __m128d, _pd);
及其朋友不应该工作,因为#if
在预处理过程中不起作用。
由于sizeof()
主题严重污染了结果,因此搜索解决方案出乎意料。谁能告诉我如何针对这个问题做出宏观层面的决定呢?
PS:我听说过Boost Preprocessor,但我不允许使用它。
更新虽然我要求提供宏解决方案,但我也会接受一个不错的模板解决方案。为此,要知道我至少要封装7个内在函数 - 以防万一会破坏模板代码。
答案 0 :(得分:0)
您可以通过特征摆脱第二个参数:
template <class Scalar>
struct Vector;
template <>
struct Vector<float>
{
typedef __m128 type;
};
template <>
struct Vector<double>
{
typedef __m128d type;
};
至于第三个,你可以做一个真正的丑陋的特殊预处理器 hack 技巧:
#define SUFFIX_float ps
#define SUFFIX_double pd
并在##
上使用SUFFIX_
和最外层的宏参数来获得正确的版本。当然,它需要一些间接级别才能使宏在正确的时间扩展。使用Boost.Preprocessor,特别是BOOST_PP_CAT
和可能BOOST_PP_EXPAND
,可能会使这一点变得更容易。