pmullw: перемножает слова из 8 дорожек, младшее слово результата помещается в итоговую дорожку
vpmullw: перемножает слова из 8 дорожек (128-битная версия) или из 16 дорожек (256-битная версия), младшее слово результата помещается в итоговую дорожку
pmulhuw: перемножает беззнаковые слова из 8 дорожек, старшее слово результата помещается в итоговую дорожку
vpmulhuw: перемножает слова из 8 дорожек (128-битная версия) или из 16 дорожек (256-битная версия), старшее слово результата помещается в итоговую дорожку
pmulhw: перемножает слова со знаком из 8 дорожек, старшее слово результата помещается в итоговую дорожку
vpmulhw: перемножает слова из 8 дорожек (128-битная версия) или из 16 дорожек (256-битная версия), старшее слово результата помещается в итоговую дорожку
pmulld: перемножает двойные слова (dword) из 4 дорожек, младшее двойное слово результата помещается в итоговую дорожку
Схематично это выглядит так:
Temp0[63:0] := SRC1[31:0] * SRC2[31:0] Temp1[63:0] := SRC1[63:32] * SRC2[63:32] Temp2[63:0] := SRC1[95:64] * SRC2[95:64] Temp3[63:0] := SRC1[127:96] * SRC2[127:96] DEST[31:0] := Temp0[31:0] DEST[63:32] := Temp1[31:0] DEST[95:64] := Temp2[31:0] DEST[127:96] := Temp3[31:0] DEST[MAXVL-1:128] := 0
vpmulld: перемножает двойные слова из 4 дорожек (128-битная версия) или из 8 дорожек (256-битная версия), младшее двойное слово результата помещается в итоговую дорожку
Схематично это выглядит так (для 128-битной версии):
Temp0[63:0] := SRC1[31:0] * SRC2[31:0] Temp1[63:0] := SRC1[63:32] * SRC2[63:32] Temp2[63:0] := SRC1[95:64] * SRC2[95:64] Temp3[63:0] := SRC1[127:96] * SRC2[127:96] DEST[31:0] := Temp0[31:0] DEST[63:32] := Temp1[31:0] DEST[95:64] := Temp2[31:0] DEST[127:96] := Temp3[31:0] DEST[MAXVL-1:128] := 0
Для 256-разрядной версии
Temp0[63:0] := SRC1[31:0] * SRC2[31:0] Temp1[63:0] := SRC1[63:32] * SRC2[63:32] Temp2[63:0] := SRC1[95:64] * SRC2[95:64] Temp3[63:0] := SRC1[127:96] * SRC2[127:96] Temp4[63:0] := SRC1[159:128] * SRC2[159:128] Temp5[63:0] := SRC1[191:160] * SRC2[191:160] Temp6[63:0] := SRC1[223:192] * SRC2[223:192] Temp7[63:0] := SRC1[255:224] * SRC2[255:224] DEST[31:0] := Temp0[31:0] DEST[63:32] := Temp1[31:0] DEST[95:64] := Temp2[31:0] DEST[127:96] := Temp3[31:0] DEST[159:128] := Temp4[31:0] DEST[191:160] := Temp5[31:0] DEST[223:192] := Temp6[31:0] DEST[255:224] := Temp7[31:0] DEST[MAXVL-1:256] := 0
vpmullq: перемножает четверные слова из 2 дорожек (128-битная версия) или из 4 дорожек (256-битная версия), младшее четверное слово результата помещается в итоговую дорожку
Проблема умножения дорожек связана с тем, что при умножении двух n-битных чисел результат надо помещать в дорожку, которая занимает n бит, хотя умножение n × n может дать результат 2×n бит. Таким образом, операция умножения по дорожкам создает проблемы, поскольку теряется переполнение. Подобные инструкции предполагают, что результат может занять 2*n бит, однако в итоговую дорожку регистра помещается только младшие или старшие n бит результата.
Синтаксис инструкций:
pmullw xmmdest, xmmsrc/mem128 vpmullw xmmdest, xmmsrc, xmm/mem128 vpmullw ymmdest, ymmsrc, ymm/mem256 pmulhuw xmmdest, xmmsrc/mem128 vpmulhuw xmmdest, xmmsrc, xmm/mem128 vpmulhuw ymmdest, ymmsrc, ymm/mem256 pmulhw xmmdest, xmmsrc/mem128 vpmulhw xmmdest, xmmsrc, xmm/mem128 vpmulhw ymmdest, ymmsrc, ymm/mem256 pmulld xmmdest, xmmsrc/mem128 vpmulld xmmdest, xmmsrc, xmm/mem128 vpmulld ymmdest, ymmsrc, ymm/mem256 vpmullq xmmdest, xmmsrc, xmm/mem128 vpmullq ymmdest, ymmsrc, ymm/mem256
Ряд инструкций позволяют обойти ограничения на разрядность результата
pmuldq: умножает двойные слова (dword) со знаком в 32-битных дорожках 0 и 2 и сохраняет 64-битные результаты в 64-битных дорожках 0 и 1 (они же 32-битные дорожки 0, 1, 2 и 3). Старшие 128 бит перекрывающего регистра YMM остаются без изменений
pmuludq: умножает беззнаковые двойные слова в 32-битных дорожках 0 и 2 и сохраняет 64-битные результаты в 64-битных дорожках 0 и 1 (они же 32-битные дорожки 0, 1, 2 и 3). Старшие 128 бит перекрывающего регистра YMM остаются без изменений
vpmuldq: 256-битные варианты умножает двойные слова со знаком в 32-битных дорожках 0, 2, 4, 6 и сохраняет 64-битные результаты
в 64-битных дорожках 0, 1, 2 и 3 (они же 32-битные дорожки 0, 1, 2, 3 и 4, 5, 6, 7). 128-битная аналогична pmuldq
за тем исключением, что старшие 128 бит перекрывающего регистра YMM заполняются нулями
vpmuludq: 256-битные варианты умножает беззнаковые двойные слова в 32-битных дорожках 0, 2, 4, 6 и сохраняет 64-битные результаты
в 64-битных дорожках 0, 1, 2 и 3 (они же 32-битные дорожки 0, 1, 2, 3 и 4, 5, 6, 7). 128-битная аналогична pmuludq
за тем исключением, что старшие 128 бит перекрывающего регистра YMM заполняются нулями
Синтаксис инструкций:
pmuldq xmmdest, xmmsrc/mem128 vpmuldq xmmdest, xmmsrc1, xmm/mem128 vpmuldq ymmdest, ymmsrc1, ymm/mem256 pmuludq xmmdest, xmmsrc/mem128 vpmuludq xmmdest, xmmsrc1, xmm/mem128 vpmuludq ymmdest, ymmsrc1, ymm/mem256
И еще пара инструкций - pclmulqdq и vpclmulqdq умножают четверные слова (qword) и сохраняют 128-битныq результат.
pclmulqdq
оставляет старшие 128 бит перекрывающего регистра YMM без изменений, а vpclmulqdq
заполняет их нулями.
pclmulqdq xmmdest, xmmsrc/mem128, imm8 vpclmulqdq xmmdest, xmmsrc1, xmmsrc2/mem128, imm8
Операнд imm8 указывает, какие четверные слова использовать в качестве исходных операндов. На примере pclmulqdq
:
imm8 | Результат |
00h | XMMdest = xmmdest[0-63] * XMM/mem128[0-63] |
01h | XMMdest = xmmdest[64-127] * XMM/mem128[0-63] |
10h | XMMdest = xmmdest[0-63] * XMM/mem128[64-127] |
11h | XMMdest = xmmdest[64-127] * XMM/mem128[64-127] |
vpclmulqdq
работает аналогично, только числа берутся из второго и третьего операнда.
Пример умножения 128-разрядных чисел:
.data nums0 word 1, 2, 3, 4, 5, 6, 7, 8 nums1 word 2, 3, 4, 5, 6, 7, 8, 9 .code main proc movdqa xmm0, oword ptr nums0 movdqa xmm1, oword ptr nums1 pmullw xmm0, xmm1 ; XMM0 = XMM0 * XMM1 ; XMM0 = 2, 6, 12, 20, 30, 42, 56, 81 ret main endp end