2015-01-05 2 views

ответ

3

Вы имеете в виду, что у вас есть байт в LSB регистра XMM и хотите дублировать его по всем полосам этого регистра? Я не знаю синтаксис ассемблера встроенный в Delphi, но в синтаксисе Intel/MASM это можно было бы сделать что-то вроде этого:

punpcklbw xmm0,xmm0 ; xxxxxxxxABCDEFGH -> xxxxxxxxEEFFGGHH 
punpcklwd xmm0,xmm0 ; xxxxxxxxEEFFGGHH -> xxxxxxxxGGGGHHHH 
punpckldq xmm0,xmm0 ; xxxxxxxxGGGGHHHH -> xxxxxxxxHHHHHHHH 
punpcklqdq xmm0,xmm0 ; xxxxxxxxHHHHHHHH -> HHHHHHHHHHHHHHHH 
+0

Да, это идея. Как загрузить начальный байт в LSB? Ссылки, которые я нашел, снова ориентированы на поплавки. – IamIC

+1

Инструкция 'MOVD' позволяет перемещать содержимое 32-разрядного регистра или ячейки памяти в регистр' xmm'. – Michael

+0

Я предполагаю, что последняя инструкция должна читать «punpcklqdq» :) – IamIC

4

ответ Майкла будет работать. В качестве альтернативы, если вы можете принять набор команд SSSE3, то с использованием Упакованные в случайном порядке байтыpshufb также будут работать.

Предполагая, что (1) 8-битное значение в AL (например) и (2) желаемый пункт назначения широковещательной передачи, чтобы быть XMM1, и (3), что еще один регистр, скажем XMM0, доступен, это будет делать трюк :

movd xmm1, eax ;// move value in AL (part of EAX) into XMM1 
pxor xmm0, xmm0 ;// clear xmm0 to create the appropriate mask for pshufb 
pshufb xmm1, xmm0 ;// broadcast lowest value into all slots of xmm1 

И да, BASM Delphi понимает SSSE3.

2

Самый быстрый вариант - SSSE3 для pshufb, если он доступен.

; SSSE3 
pshufb  xmm0, xmm1  ; where xmm1 is zeroed, e.g. with pxor xmm1,xmm1 

В противном случае вы обычно должны использовать это:

; SSE2 only 
punpcklbw xmm0, xmm0  ; xxxxxxxxABCDEFGH -> xxxxxxxxEEFFGGHH 
pshuflw  xmm0, xmm0, 0  ; xxxxxxxxEEFFGGHH -> xxxxxxxxHHHHHHHH 
punpcklqdq xmm0, xmm0  ; xxxxxxxxHHHHHHHH -> HHHHHHHHHHHHHHHH 

Это лучше, чем punpckl м.т./БВ ->pshufd xmm0, xmm0, 0, потому что есть some CPUs with only 64-bit shuffle units. (Including Merom and K8). На таких процессорах pshuflw быстр, а также punpcklqdq, но pshufd и punpck с зернистостью менее 64 бит медленный. Таким образом, эта последовательность использует только одну инструкцию «медленного тасования», против 3 для bw/wd/pshufd.

На всех последующих процессорах нет разницы между этими двумя последовательностями из 3 инструкций, поэтому в этом случае нам не нужно ничего настраивать для старых процессоров. См. Также http://agner.org/optimize/ для таблиц инструкций.

Это последовательность ответов Майкла с двумя командами, замененными на pshuflw.


Если байт, чтобы начать с целочисленного регистра, вы можете использовать умножение на 0x01010101, чтобы транслировать его на 4 байта. например

; movzx eax, whatever 

imul edx, eax, 0x01010101 ; edx = al repeated 4 times 

movd xmm0, eax 
pshufd xmm0, xmm0, 0 

Обратите внимание, что без непосредственный операнд источника imul «s может быть память, но она должна быть 32-битное расположение в памяти с нулевым байтом-продлен до 32 бит.


Если ваши данные начинаются в память, сначала загрузка в регистр целых значений, вероятно, не стоит. Просто movd в регистр xmm. (Или, возможно, pinsrb, если вам нужно избегать более широкой нагрузки, чтобы избежать пересечения страницы или, может быть, строки кэша, но это имеет ложную зависимость от старого значения регистра, где movd этого не делает.)

Если пропускная способность для команд является скорее проблемой, чем латентностью, то стоит использовать pmuludq, если вы не можете использовать pshufb, даже если на большинстве процессоров имеется 5-тикратная латентность.

; low 32 bits of xmm0 = your byte, **zero extended** 
pmuludq xmm0, xmm7  ; xmm7 = 0x01010101 in the low 32 bits 
pshufd xmm0, xmm0, 0 
+0

Вау, ты точно знаешь свой SSE. Один вопрос: как pinsrb каждый крест страницы? – IamIC

+0

@IamIC: Это не так, поэтому вы должны использовать его * вместо '' movd', чтобы получить байт в младший байт xmm-регистров. –