Вы можете достичь желаемой цели, выполняя перемешивание, а затем распаковывая. В синтаксисе NASM:
# load 16 bit from memory into all words of xmm0
# assuming 16-byte alignment
pshuflw xmm0, [mem], 0 # gives you [ M, M, M, M, ?, ?, ?, ? ]
punpcklwd xmm0, xmm0 # gives you [ M, M, M, M, M, M, M, M ]
Обратите внимание, что это читает 16 байтов из mem
и, следовательно, требует 16-байтового выравнивания .
На самом деле используются только первые 2 байта. Если номер отсутствует в памяти или вы не можете гарантировать, что чтение после конца возможно, используйте что-то вроде этого:
# load ax into all words of xmm0
movd xmm0, eax ; or movd xmm0, [mem] 4-byte load
pshuflw xmm0, xmm0, 0
punpcklwd xmm0, xmm0
В AVX2 вы можете использовать широковещательную загрузку vpbroadcast*
или широковещательную передачу из источника регистра. Пункт назначения может быть YMM, если хотите.
vpbroadcastw xmm0, [mem] ; 16-bit load + broadcast
Или
vmovd xmm0, eax
vpbroadcastw xmm0, xmm0
Широковещательные трансляции из источника памяти из 1 или 2-байтовых элементов по-прежнему декодируются в нагрузку + перемешивание на процессорах Intel, но широковещательная загрузка 4-байтовых или 8-байтовых блоков даже дешевле: обрабатывается в порту загрузки без необходим случайный ход.
В любом случае это все равно дешевле, чем 2 отдельных шаффла, как вам нужно без AVX2 или SSSE3 pshufb
.