Как переместить удвоение в% rax в определенную позицию qword на% ymm или% zmm? (Озеро Кабы или позже) - PullRequest
0 голосов
/ 13 сентября 2018

Идея состоит в том, что я хотел бы собрать возвращенные значения double в векторный регистр для обработки на машине imm width за один раз без сохранения в памяти первый.

Конкретной обработкой является vfma с двумя другими операндами, которые все constexpr, так что они могут быть просто вызваны с помощью _mm256_setr_pd или выравниванием / выравниванием загрузки памяти из constexpr array.

Есть ли способ хранить double в %ymm в определенной позиции непосредственно из значения в %rax для целей сбора?

Целевой машиной является Kaby Lake. Также приветствуются более эффективные будущие векторные инструкции.

1 Ответ

0 голосов
/ 13 сентября 2018

Встроенная сборка, как правило, плохая идея: современные компиляторы хорошо справляются со встроенными функциями x86.

Вставка битового шаблона для double в RAX обычно также не полезна и пахнет как выВозможно, вы уже пошли по неверному пути в неоптимальную территорию.Векторные инструкции тасования, как правило, лучше: поэлементные инструкции по вставке / извлечению уже стоят на аппаратном оборудовании Intel за случайное перемешивание, за исключением vmovq %xmm0, %rax, чтобы получить младший элемент.

Кроме того, если вы собираетесь его вставитьв другой вектор, вы должны перемешать / немедленное смешивание.(vpermpd / vblendpd).

L1d и кэш-память пересылки работают быстро, и даже задержки при пересылке магазина не являются катастрофой.Мудро выбирайте между ALU и памятью, чтобы собирать или разбрасывать данные в / из векторов SIMD.Также помните, что инструкции вставки / извлечения нуждаются в непосредственном индексе, поэтому, если у вас есть индекс времени выполнения для вектора, вы определенно хотите сохранить его и индексировать.(См. https://agner.org/optimize/ и другие ссылки на производительность в https://stackoverflow.com/tags/x86/info)

. Многие вставки / извлечения могут быстро стать узким местом на порту 5 в Haswell и более поздних версиях. См. Загрузка xmm из GPregs для получения более подробной информации и некоторых ссылок на отчеты об ошибках gcc, где я более подробно рассказал о стратегиях для элементов различной ширины на разных uarches и с SSE4.1 по сравнению с SSE4.1 и т. д.


Нет версии PD для extractps r/m32, xmm, imm, а insertps - это тасование между векторами XMM.

Для чтения / записи нижней полосыYMM, вам нужно использовать целое число vpextrq $1, %xmm0, %rax / pinsrq $1, %rax, %xmm0. Они не доступны в ширине YMM, поэтому вам нужно несколько инструкций для чтения / записи верхней полосы.

VEXверсия vpinsrq $1, %rax, %xmm0 обнулит верхнюю (ые) полосу (ширину) полного ширины YMM или ZMM целевого вектора, поэтому я предложил pinsrq. На Skylake и более поздних версиях он не вызовет остановку перехода SSE / AVX. См. Использование регистров ymm в качестве "памяти" хранилища для example (синтаксис NASM), а также Загрузка xmm из регистров GP

Для нижнего элемента используйте vmovq %xmm0, %rax для извлечения,это дешевле, чем vpextrq (1 моп вместо 2).


Для ZMM мой ответ на этот связанный вопрос XMM от reg-ов GP показывает, что вы можете использовать AVX512F для объединения- замаскируйте целочисленный регистр в вектор, учитывая регистр маски с одним установленным битом.

vpbroadcastq %rax, %zmm0{%k1}

Аналогично, vpcompressq может переместить элемент, выбранный с помощью однобитовой маски, в нижнюю часть для vmovq*/ vmovq %zmm2, %rax.Этот трюк работает даже с vpshufb для байтовых элементов (по крайней мере, с дорожкой).Для пересечения линии, возможно, перемешать + vmovd с старшими битами индекса байта, затем скалярное смещение вправо, используя младшие биты индекса в качестве смещения байта в слове.См. Также Как использовать функцию _mm_extract_epi8? для встроенных функций для эмуляции с переменным индексом pextrb.


High Lane YMM с AVX2

Я думаю, что вам лучше всего написать элемент в верхнем ряду YMM с AVX2, для которого нужен регистр нуля:

  • vmovq %rax, %xmm0 (скопировать в вектор нуля)
  • перемешать вположение с vinsertf128 (AVX1) или vpbroadcastq / vbroadcastsd.это быстрее, чем vpermq / vpermpd на AMD.(Но версия reg-reg по-прежнему только для AVX2)
  • vblendpd (FP) или vpblendd (целое число) в целевую рег. YMM.Немедленное смешивание с dword или большей шириной элемента очень дешево (1 моп для любого векторного порта ALU на Intel).

Это всего 3 мопа, но 2 из них нуждаются в порте 5 на процессорах Intel.(Так что это стоит столько же, сколько vpinsrq + смесь).Только смесь находится на критическом пути от векторного входа к векторному выходу, установка ymm0 из rax независима.

Чтобы прочитать самый высокий элемент, vpermpd или vpermq $3, %ymm1, %ymm0 (AVX2),затем vmovq от xmm0.

Чтобы прочитать 2-й самый высокий элемент, vextractf128 $1, %ymm1, %xmm0 (AVX1) и vmovq.vextractf128 быстрее, чем vpermq/pd на процессорах AMD.


Плохая альтернатива, позволяющая избежать нуля при вставке, будет vpermq или vperm2i128, чтобы перетасовать слово, которое вы хотите заменить нанижняя полоса, pinsrq ( не vpinsrq), затем vpermq, чтобы вернуть ее в правильном порядке.Это все случайные мопы, а pinsrq - 2 мопа.(И вызывает остановку перехода SSE / AVX на Haswell, но не Skylake).Кроме того, все эти операции являются частью цепочки зависимостей для изменяемого регистра, в отличие от установки значения в другом регистре и смешивания.

...