2014-08-27 5 views
1

В моей компании я работаю над предоставлением более быстрого SSE-пути для некоторого горячего кода. Я использую встроенный подход, который держится на C++ и действительно показывает впечатляющие результаты.Как я могу принять решение на основе типа внутри макроса?

Весь код должен работать только на float и double, поэтому я создал шаблонный класс операций SSE, который я специализировал для обоих. То, что я действительно не нравится то, что эти два класса выглядят почти идентично для типа номера (float/double), используемый тип SSE (__m128/__m128d) и intrisics суффиксом (_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. 
}; 

Я не знаю, как объединить это с помощью шаблона магии, из-за суффикса различных Intrinsics.

Тогда мне пришла в голову возможность макросов, которая одолжила бы для этой цели. Таким образом, мне удалось поставить полный специализированный класс в макрос, который я мог бы использовать для создания обоих классов с:

SSE_OPERATIONS(float, __m128, _ps); 
SSE_OPERATIONS(double, __m128d, _pd); 

Я знаю, что макросы зло и все, но, по крайней мере, в этом случае я не вижу какой-либо из типичные опасности, и он выполняет свою работу.

Что меня беспокоит, так это то, что второй и третий макропараметры являются избыточными; их можно было бы вывести из первого, только я понятия не имею, как это сделать. #if и его друзья не должны работать, потому что sizeof() не работает во время предварительной обработки.

Поиск решений неожиданно затруднен из-за #if тем, сильно загрязняющих результаты. Может ли кто-нибудь сказать мне, как сделать решение на уровне макросов для этой проблемы?

PS: Я слышал о Boost Preprocessor, но мне не разрешено использовать его.

Обновление: Хотя я прошу решение для макросов, я бы тоже принял хорошее решение для шаблонов. Для этого знайте, что я инкапсулирую как минимум 7 встроенных функций - на всякий случай, если бы раздувал код шаблона.

+0

Если вы можете сделать это с помощью макроса, вы можете сделать это без макроса. –

+1

Я не вижу, как макро параметры являются избыточными. Эти 3 имени полностью не связаны на уровне маркера.Ваш макрос должен по необходимости указывать логическую связь между этими тремя токами. Вы просто не можете вывести '_ps' из' float'. Конечно, это в конечном итоге вызвано крайне ограниченной интеграцией SSE-примитивов и C++. Если бы ответственный разработчик компилятора понял и то, и другое, он бы понял, что 'operator +' является совершенно нормальным именем для '_mm_add_pd'. Перегрузка оператора составляет несколько десятков лет; не нужно продолжать вводить ограничения ассемблера на программы сегодня. – MSalters

+0

Хорошо, они не избыточны для ПП, но для меня. Если бы у меня был макрос, если бы я мог просто вычислить/установить их в начале макроса, заданного только 'float' или' double'. – primfaktor

ответ

0

Вы можете избавиться от второго параметра с помощью признака:

template <class Scalar> 
struct Vector; 

template <> 
struct Vector<float> 
{ 
    typedef __m128 type; 
}; 

template <> 
struct Vector<double> 
{ 
    typedef __m128d type; 
}; 

Что касается третьего, то вы можете сделать действительно уродливую специальный препроцессор взломать трюк:

#define SUFFIX_float ps 
#define SUFFIX_double pd 

и используйте ## по адресу SUFFIX_, а внешний параметр макроса - для правильной версии. Конечно, для того, чтобы макросы расширялись в правильное время, потребовалось бы несколько уровней косвенности. Использование Boost.Preprocessor, в частности BOOST_PP_CAT и, возможно, BOOST_PP_EXPAND, может сделать это немного проще.