#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.