VPERMIL2PS и VPERMIL2PD Все инструкции PERMIL2 удалены - Замена отсутствующих инструкций

Как я могу заменить отсутствующую инструкцию VPERMIL2PS, используя эквивалентные инструкции в AVX2?

VPERMIL2PS ymm1, ymm2, ymm3, ymm4/m256, imz2

Переставьте значения с плавающей запятой одинарной точности в ymm2 и ymm3, используя элементы управления из ymm4 / mem, результаты сохраняются в ymm1 с выборочными элементами управления с нулевым совпадением.

VPERMIL2PS (VEX.256 encoded version)
DEST[31:0]  sel_and_condzerosp(SRC1[127:0], SRC2[127:0], SRC3[3:0])
DEST[63:32]  sel_and_condzerosp(SRC1[127:0], SRC2[127:0], SRC3[35:32])
DEST[95:64]  sel_and_condzerosp(SRC1[127:0], SRC2[127:0], SRC3[67:64])
DEST[127:96]  sel_and_condzerosp(SRC1[127:0], SRC2[127:0], SRC3[99:96])
DEST[159:128]  sel_and_condzerosp(SRC1[255:128], SRC2[255:128], SRC3[131:128])
DEST[191:160]  sel_and_condzerosp(SRC1[255:128], SRC2[255:128], SRC3[163:160])
DEST[223:192]  sel_and_condzerosp(SRC1[255:128], SRC2[255:128], SRC3[195:192])
DEST[255:224]  sel_and_condzerosp(SRC1[255:128], SRC2[255:128], SRC3[227:224])

Внутренний эквивалент компилятора Intel C / C ++

VPERMIL2PS __m128 _mm_permute2_ps (__m128 a, __m128 b, __m128i ctrl, int imm)
VPERMIL2PS __m256 _mm256_permute2_ps (__m256 a, __m256 b, __m256i ctrl, int imm)

VPERMIL2PS ymm1, ymm2, ymm3, ymm4 / m256, imz2 Описание - Перестановка значений с плавающей запятой одинарной точности в ymm2 и ymm3 с использованием элементов управления из ymm4 / mem, результаты сохраняются в ymm1 с выборочными элементами управления с нулевым совпадением. imz2: Часть непосредственного байта is4, обеспечивающая функции управления, которые применяются к инструкциям перестановки с двумя источниками.

Ближайшая инструкция - VPERMILPS .. и эта инструкция до сих пор работает

VPERMILPS (256-bit immediate version)
DEST[31:0]  Select4(SRC1[127:0], imm8[1:0]);
DEST[63:32]  Select4(SRC1[127:0], imm8[3:2]);
DEST[95:64]  Select4(SRC1[127:0], imm8[5:4]);
DEST[127:96]  Select4(SRC1[127:0], imm8[7:6]);
DEST[159:128]  Select4(SRC1[255:128], imm8[1:0]);
DEST[191:160]  Select4(SRC1[255:128], imm8[3:2]);
DEST[223:192]  Select4(SRC1[255:128], imm8[5:4]);
DEST[255:224]  Select4(SRC1[255:128], imm8[7:6]);

VPERMILPS ymm1, ymm2, ymm3 / m256 Описание - RVM V / V AVX Перестановка значений с плавающей запятой одинарной точности в ymm2 с помощью элементов управления из ymm3 / mem и сохранение результата в ymm1.

Насколько это будет правильно, мне сказать сложно, потому что для надежности нужно эмулировать инструкцию VPERMIL2PS, поэтому обращаюсь к местным специалистам!

Последние архитектурные изменения Intel (R) AVX 29 января 2009 г. Удалены: VPERMIL2PS и VPERMIL2PD

Все инструкции PERMIL2 исчезли - как в 128-битном, так и в 256-битном вариантах. Как и в FMA ниже, они использовали бит VEX.W для выбора источника из памяти - мы больше не движемся в направлении использования VEX.W для этой цели.

Компилятор Intel не понимает эту инструкцию VPERMIL2PS.

Для инструкций AVX-512 требуются новейшие процессоры, это не общее решение. Visual Studio успешно собирает эту инструкцию, но инструкция не может быть выполнена на процессоре, вызывая исключение.

Дизассемблированный код

align 20h;
Yperm_msk ymmword 000000000100000006000000070000000C0000000D0000000A0000000B000000h

                vmovups ymm0, [rbp+920h+var_8C0]
                vmovdqu ymm1, Yperm_msk
                vpermil2ps ymm0, ymm0, [rbp+920h+var_880], ymm1, 920h+var_920
                vmovups [rbp+920h+var_1A0], ymm0

Полное описание инструкции

Операция

select2sp(src1, src2, sel) // This macro is used by another macro “sel_and_condzerosp“ below
{
if (sel[2:0]=0) then TMP  src1[31:0]
if (sel[2:0]=1) then TMP  src1[63:32]
if (sel[2:0]=2) then TMP  src1[95:64]
if (sel[2:0]=3) then TMP  src1[127:96]
if (sel[2:0]=4) then TMP  src2[31:0]
if (sel[2:0]=5) then TMP  src2[63:32]
if (sel[2:0]=6) then TMP  src2[95:64]
if (sel[2:0]=7) then TMP  src2[127:96]
return TMP
}
sel_and_condzerosp(src1, src2, sel) // This macro is used by VPERMIL2PS
{
TMP[31:0]  select2sp(src1[127:0], src2[127:0], sel[2:0])
IF (imm8[1:0] = 2) AND (sel[3]=1) THEN TMP[31:0]  0
IF (imm8[1:0] = 3) AND (sel[3]=0) THEN TMP[31:0]  0
return TMP
}

VPERMIL2PS (версия с кодировкой VEX.256)

DEST[31:0]  sel_and_condzerosp(SRC1[127:0], SRC2[127:0], SRC3[3:0])
DEST[63:32]  sel_and_condzerosp(SRC1[127:0], SRC2[127:0], SRC3[35:32])
DEST[95:64]  sel_and_condzerosp(SRC1[127:0], SRC2[127:0], SRC3[67:64])
DEST[127:96]  sel_and_condzerosp(SRC1[127:0], SRC2[127:0], SRC3[99:96])
DEST[159:128]  sel_and_condzerosp(SRC1[255:128], SRC2[255:128], SRC3[131:128])
DEST[191:160]  sel_and_condzerosp(SRC1[255:128], SRC2[255:128], SRC3[163:160])
DEST[223:192]  sel_and_condzerosp(SRC1[255:128], SRC2[255:128], SRC3[195:192])
DEST[255:224]  sel_and_condzerosp(SRC1[255:128], SRC2[255:128], SRC3[227:224])

То, как Bochs подражает этой инструкции

class bxInstruction_c;

void BX_CPP_AttrRegparmN(1) BX_CPU_C::VPERMIL2PS_VdqHdqWdqIbR(bxInstruction_c *i)
{
  BxPackedYmmRegister op1 = BX_READ_YMM_REG(i->src1());
  BxPackedYmmRegister op2 = BX_READ_YMM_REG(i->src2());
  BxPackedYmmRegister op3 = BX_READ_YMM_REG(i->src3()), result;
  unsigned len = i->getVL();

  result.clear();

  for (unsigned n=0; n < len; n++) {
    xmm_permil2ps(&result.ymm128(n), &op1.ymm128(n), &op2.ymm128(n), &op3.ymm128(n), i->Ib() & 3);
  }

  BX_WRITE_YMM_REGZ_VLEN(i->dst(), result, len);

  BX_NEXT_INSTR(i);
}

BX_CPP_INLINE void xmm_permil2ps(BxPackedXmmRegister *r, const BxPackedXmmRegister *op1, const BxPackedXmmRegister *op2, const BxPackedXmmRegister *op3, unsigned m2z)
{
  for(unsigned n=0; n < 4; n++) {
    Bit32u ctrl = op3->xmm32u(n);
    if ((m2z ^ ((ctrl >> 3) & 0x1)) == 0x3)
      r->xmm32u(n) = 0;
    else
      r->xmm32u(n) = (ctrl & 0x4) ? op1->xmm32u(ctrl & 0x3) : op2->xmm32u(ctrl & 0x3);
  }
}

person KingBugmenot    schedule 18.08.2019    source источник
comment
Я обновил свой ответ, добавив больше подробностей о вариантах AVX1 для создания одного и того же перемешивания из нескольких инструкций.   -  person Peter Cordes    schedule 18.08.2019


Ответы (1)


Они не «ушли», они вообще никогда не существовали ни в каких реальных процессорах. В 2009 году был выпущен первый процессор с AVX1, тогда как AVX все еще находился на стадии планирования. IDK то, что вы смотрели, даже упомянуло их.

Текущие версии справочного руководства ISA или выдержки из HTML не упоминают это . Также нет Руководство Intel по встроенным функциям. Может быть, это 10-летняя версия руководства по «будущим расширениям», созданная до того, как был выпущен Sandybridge?

потому что для надежности нужно эмулировать инструкцию VPERMIL2PS

Нет, его вообще никогда не было, поэтому нет кода, который его использует. (Или очень мало; возможно, некоторые написаны с опережением на основе ранней предварительной документации AVX). Вам нужно только реализовать именно ту функциональность, которая вам нужна для каждой конкретной проблемы.

Вы отметили этот (AMD) XOP, но цитировали только документы Intel; Я думаю, что у XOP было несколько перестановок с двумя входами, но я не стал проверять документацию. Конечно, только для 128-битных векторов.


В AVX1 есть несколько вариантов случайного выбора с двумя входами, но с переменным управлением нет ни одного. Есть vshufps / pd с немедленным управлением и _ 3_ и ...pd, которые выполняют две отдельные линейные версии соответствующего 128-битного перемешивания.

В худшем случае вы можете построить любой фиксированный перетасовка с двумя входами из 2x vshufps + vblendps. В лучшем случае - один vshufps, или посередине - vshufps + vblendps или 2x vshufps (например, собрать элементы, которые вы хотите объединить в один вектор, затем поместите их в правильном порядке). Любой из этих vshufps перемешиваний может быть vunpcklps или hps. Имейте в виду, что немедленный vblendps дешев, но перемешивание имеет пропускную способность только 1 / такт на Intel (порт 5 только до Ice Lake).

Вы даже можете использовать управление переменными 2x vpermilps и сравнить или сдвинуть + vblendvps для эмуляции vpermil2ps, потому что vpermilps игнорирует старшие биты в индексе. Таким образом, это будет реализация BOCHS для (ctrl & 0x4) ? op2[ctrl & 0x3] : op2[ctrl & 0x3];, где вы перетасовываете оба входа на ctrl с vpermilps (который неявно смотрит только на младшие 2 бита), а вы смешиваете ctrl & 4, сдвигая этот бит вверх с целочисленным сдвигом.

(При желании можно также эмулировать условное обнуление с помощью vandps, используя vpslld, чтобы поместить 3-й индексный бит вверху для смешивания, и vpsrad или результат сравнения с нулем, чтобы создать маску И для vpand. Или в Skylake vblendvps равно 2 мупа для любого порта, чтобы вы могли просто использовать это для смешивания нулей вместо shift / и или cmp / и).

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


AVX2 только добавил несколько новых тасовок с двумя входами, которые могут быть здесь полезны: 256-битные vpalignr, что похоже на 2-полосные palignr инструкции. Он также добавил целое число vpunpckl/h b/w/d/q, но у нас уже есть vunpckl/hps из AVX1.


Настоящее перемешивание с двумя входами с переменным управлением не появлялось до появления AVX512F vpermt2ps и _ 33 _ / _ 34_.

Но он не поддерживает условное обнуление, основанное на старших битах элементов индекса, таких как pshufb или предлагаемый vpermil2ps; вместо этого используйте регистр маски для нулевой маскировки. например

  vmovd2m    k1, ymm0                              ; extract top bit of dword elements
  knotw      k1, k1                                ; cleared for elements to be zeroed
  vpermi2ps  ymm0{k1}{z}, ymm0, ymm1, ymm2         ; ymm0=indices   ymm1,ymm2 = table
  ; indices overwritten with result
  ; use vpermt2ps instead to overwrite one of the "table" inputs instead of the index vector.

Или, возможно, лучше использовать vpfclassps k1, ymm0, some_constant, чтобы установить k1 для неотрицательных значений, избегая необходимости в knot. На Skylake-X это единственный моп.

Или используйте vptestnmd с маской set1(1UL<<31), чтобы установить регистр маски = !signbit вектора.


Это также не "в полосе", поэтому вам потенциально может потребоваться настроить индексы, добавив 8 для индексов> 4, я думаю. vpermi/t2ps индексирует конкатенацию двух векторов, поэтому переход в пределах одного источника происходит до выбора другого входа.

person Peter Cordes    schedule 18.08.2019
comment
Вот документ, описывающий использование этой инструкции - software.intel.com/sites/default/files/m/d/4/1/d/8/ И вот готовый проект с этой прокомментированной инструкцией - mega.co.nz/ - person KingBugmenot; 18.08.2019
comment
Вот этот закомментированный код .. Спасибо, попробую разобраться! Yt1 = _mm256_hadd_ps (Yt1, Yt4); Yt0 = _mm256_permute2_ps (Yt0, Yt2, (__m256i) Yperm_msk, 0); ‹--- _mm256_store_ps (P, _mm256_add_ps (Yt0, Yt1)); dY + = 48; P + = 8; - person KingBugmenot; 18.08.2019
comment
@Kingbugmenot: тогда вам следует спросить конкретно об этом варианте использования. Условное обнуление нужно или нет? И является ли Yperm константой времени компиляции? Думаю, может, и нет; фильтр Ланцоша знает, какие позиции данных ему нужны; только значения изменчивы. В любом случае, обратите внимание, что этот технический документ датируется апрелем 2008 года, за годы до настоящего ЦП. - person Peter Cordes; 18.08.2019