Конфликт при перегрузке векторными типами __m128, __m256 в GCC

#gcc #operator-overloading #sse #avx #mingw-w64

#gcc #оператор-перегрузка #sse #avx #mingw-w64

Вопрос:

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

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

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

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

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

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

Ответ №1:

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

добавьте -fabi-version=4 опцию компилятора.

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

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

Комментарии:

1. Обратите внимание, что начиная с gcc-5, это больше не требуется, поскольку значение по умолчанию -fabi-version было изменено.

2. Это исправление проблемы, с которой GCC сталкивается с кодом AVX / AVX2 в 64-разрядной версии Windows?

Ответ №2:

Я был недоволен решением по изменению флагов ABI компилятора для решения этой проблемы, поэтому я пошел искать другое решение. Кажется, они столкнулись с этой проблемой при написании собственной библиотеки — смотрите Этот исходный файл для деталей 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 Tamp;() { return myValue; }
    inline operator const Tamp;() const { return myValue; }
    inline Register() {}
    inline Register(const T amp; v) : myValue(v) {} // Not explicit
    inline Register amp; operator=(const T amp; 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.