Конфликт перегрузки с векторными типами __m128, __m256 в GCC - PullRequest
3 голосов
/ 08 мая 2011

Я начал играть с инструкциями AVX на новом процессоре Intel Sandy Bridge.Я использую GCC 4.5.2, 64-битную сборку TDM-GCC MinGW64.

Я хочу перегрузить оператор << для того, чтобы ostream мог выводить на консоль векторные типы <code>__m256, __m128 и т. Д.Но я сталкиваюсь с конфликтом перегрузки.Вторая функция в следующем коде выдает ошибку «конфликтует с предыдущим объявлением void f(__vector(8) float)»:

void f(__m128 v) {
cout << 4;
}

void f(__m256 v) {
    cout << 8;
}

Похоже, что компилятор не может различить два типа и учитывает их оба f(float __vector).

Есть ли способ обойти это?Я не смог ничего найти в Интернете.Любая помощь с благодарностью.

Ответы [ 2 ]

4 голосов
/ 10 мая 2011

Я случайно наткнулся на ответ при возникновении аналогичной проблемы с шаблонами функций. В этом случае сообщение об ошибке GCC фактически предлагает решение:

add -fabi-version=4 опция компилятора.

Это решает мою проблему и, надеюсь, не вызывает проблем при связывании стандартных библиотек.

Подробнее о ABI (двоичный интерфейс приложения) и GCC можно прочитать в Политика и рекомендации ABI и Спецификация ABI . ABI определяет, как имена функций искажаются, когда код компилируется в объектные файлы. Очевидно, ABI версии 3, используемая GCC по умолчанию, не может различить различные типы векторов.

1 голос
/ 04 декабря 2014

Я был недоволен решением изменить флаги ABI компилятора для решения этой проблемы, поэтому я отправился на поиски другого решения. Кажется, они столкнулись с этой проблемой при написании библиотеки Eigen - подробности см. В этом исходном файле http://eigen.tuxfamily.org/dox-devel/SSE_2PacketMath_8h_source.html

Мое решение это слегка подправленная версия:

template <typename T, unsigned RegisterSize>
struct Register
{
    using ValueType = T;
    enum { Size = RegisterSize };

    inline operator T&() { return myValue; }
    inline operator const T&() const { return myValue; }
    inline Register() {}
    inline Register(const T & v) : myValue(v) {} // Not explicit
    inline Register & operator=(const T & v)
    {
        myValue = v;
        return *this;
    }

    T myValue;
};

using Register4 = Register<__m128, 4u>;
using Register8 = Register<__m256, 8u>;
// Could provide more declarations for __m128d, __m128i, etc. if needed

Используя вышеизложенное, вы можете перегружать Register4, Register8 и т. Д. Или создавать шаблонные функции за Register с, не сталкиваясь с проблемами связывания и не меняя настроек ABI.

...