Совместимость типов данных с внутренними функциями NEON

Я работаю над оптимизацией ARM с использованием встроенных функций NEON из кода C ++. Я понимаю и справляюсь с большинством проблем с набором текста, но я застрял на этом:

Инструкция vzip_u8 возвращает значение uint8x8x2_t (фактически массив из двух uint8x8_t). Я хочу присвоить возвращаемое значение простому uint16x8_t. Я не вижу подходящего vreinterpretq внутреннего для достижения этого, и простые преобразования отклоняются.


person Yves Daoust    schedule 04.12.2012    source источник
comment
Только что обнаружил в руководстве, что uint8x8x2_t называется типом данных векторного массива. Но до сих пор не знаю, как конвертировать.   -  person Yves Daoust    schedule 05.12.2012
comment
Можете ли вы опубликовать небольшой фрагмент, чтобы продемонстрировать свой вопрос?   -  person auselen    schedule 07.12.2012


Ответы (5)


На некоторые определения ответить четко ...

NEON имеет 32 регистра, шириной 64 бита (двойное представление как 16 регистров, шириной 128 бит).

Блок NEON может просматривать тот же банк регистров, что и:

  • шестнадцать 128-битных регистров четверного слова, Q0-Q15
  • тридцать два 64-битных регистра двойного слова, D0-D31.

uint16x8_t - это тип, для которого требуется 128-битное хранилище, поэтому он должен находиться в регистре quadword.

В ARM NEON Intrinsics есть определение vector array data type в языке ARM® C Расширения:

... для использования в операциях загрузки и сохранения, в операциях поиска по таблицам и в качестве результата операций, возвращающих пару векторов.

Инструкция по vzip

... чередует элементы двух векторов.

vzip Dd, Dm

и имеет внутренний, например

uint8x8x2_t vzip_u8 (uint8x8_t, uint8x8_t) 

из них мы можем заключить, что uint8x8x2_t на самом деле является списком из двух случайных пронумерованных регистров двойного слова, потому что инструкции vzip не имеют никаких требований к порядку входных регистров.

Теперь ответ ...

uint8x8x2_t может содержать два непоследовательных регистра двойного слова, а uint16x8_t - это структура данных, состоящая из двух последовательных регистров двойного слова, первый из которых имеет четный индекс (D0-D31 -> Q0-Q15).

Из-за этого вы не можете преобразовать vector array data type с двумя регистрами двойного слова в регистр четверного слова ... легко.

Компилятор может быть достаточно умен, чтобы помочь вам, или вы можете просто принудительно преобразовать, но я бы проверил полученную сборку на правильность и производительность.

person auselen    schedule 06.12.2012
comment
Теперь все прояснилось, спасибо. uint8x8x2_t должен быть псевдотипом, поскольку он описывает, возможно, несмежные данные. Но мой первоначальный вопрос остается: вы можете просто принудительно преобразовать. Как ??? - person Yves Daoust; 06.12.2012
comment
Но, как я уже сказал, компилятор может исправить это за вас. Проблема в том, что производительность может снизиться. Вы должны проверить двоичный файл. - person auselen; 06.12.2012
comment
Моя проблема заключалась в том, что я не мог найти способ заставить компилятор принимать приведение. - person Yves Daoust; 07.12.2012
comment
Я думал, что вы сделали, как в своем собственном ответе. - person auselen; 07.12.2012
comment
Дело в том, что я не доверяю этому решению, которое могло сработать случайно. Придется проверить это глубже ... - person Yves Daoust; 07.12.2012
comment
В руководстве, на которое вы ссылаетесь (Раздел 12.2.2), int16x4x2_t определяется как struct int16x4x2_t {int16x4_t val [2]; } ;. Правильно ли при разработке альтернативного оператора литья обрабатывать 2 массива, как если бы они находились в последовательных ячейках памяти (поскольку они объявлены как хранящиеся в массиве массивов)? - person Antonio; 25.03.2015
comment
@Antonio Afaik, это в основном для регистров приведения, как расположение вещей в памяти может быть совершенно другой историей. Проверьте инструкцию VLDM. - person auselen; 25.03.2015
comment
Не могли бы вы взглянуть на this и посмотрите, есть ли в этом смысл? - person Antonio; 25.03.2015

Вы можете построить 128-битный вектор из двух 64-битных векторов, используя встроенные функции vcombine_ *. Таким образом, вы можете вот так добиться того, чего хотите.

#include <arm_neon.h>

uint8x16_t f(uint8x8_t a, uint8x8_t b)
{
    uint8x8x2_t tmp = vzip_u8(a,b);
    uint8x16_t result;
    result = vcombine_u8(tmp.val[0], tmp.val[1]);
    return result;
}
person Charles Baylis    schedule 22.09.2014
comment
Интересно, спасибо. Я займусь этим (но, скорее всего, не скоро, это спящий проект). - person Yves Daoust; 23.09.2014

Я нашел обходной путь: учитывая, что член val типа uint8x8x2_t является массивом, он поэтому рассматривается как указатель. Приведение и отсчет указателя работают! [Принимая во внимание адрес данных, возникает предупреждение "адрес временного".]

uint16x8_t Value= *(uint16x8_t*)vzip_u8(arg0, arg1).val;

Оказывается, это компилируется и выполняется как следует (по крайней мере, в случае, который я пробовал). Я не смотрел код сборки, поэтому не могу гарантировать, что он реализован должным образом (я имею в виду просто сохранение значения в регистре вместо записи / чтения в / из памяти.)

person Yves Daoust    schedule 05.12.2012
comment
Я не эксперт, но думаю, что это нарушит строгие правила использования псевдонимов. Плюс риск, упомянутый auselan, что два вектора векторов не связаны в одном и том же 128-битном регистре. - person Antonio; 25.03.2015
comment
С чисто декларативной точки зрения два вектора в структуре должны быть смежными, и это безобидно. Таким образом, мы должны предположить, что компилятор будет обрабатывать соответствующие передачи между памятью и регистрами. - person Yves Daoust; 25.03.2015
comment
Вы правы в этом вопросе. Тем не менее, технически существует строгое нарушение правил псевдонима. - person Antonio; 25.03.2015

Я столкнулся с той же проблемой, поэтому я представил гибкий тип данных.

Поэтому теперь я могу определить следующее:

typedef NeonVectorType<uint8x16_t> uint_128bit_t; //suitable for uint8x16_t, uint8x8x2_t, uint32x4_t, etc.
typedef NeonVectorType<uint8x8_t> uint_64bit_t; //suitable for uint8x8_t, uint32x2_t, etc.
person Antonio    schedule 24.03.2015

Это ошибка в GCC (теперь исправленная) в сериях 4.5 и 4.6.

Ссылка на Bugzilla http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48252

Пожалуйста, возьмите исправление этой ошибки, примените к исходному тексту gcc и перестройте его.

person BHS    schedule 04.09.2013
comment
Привет. Спасибо за участие в публикации. Однако он не решает текущую проблему, которая связана с синтаксической / семантической несовместимостью, а не с ошибкой генерации кода в компиляторе. - person Yves Daoust; 05.09.2013