向Delphi ASM中的所有16个XMM插槽广播一个字节值

时间:2015-01-05 13:15:29

标签: delphi assembly delphi-7 sse basm

使用VBROADCASTS命令在AVX中很容易,如果值是双精度或浮点数,则在SSE中很容易。

如何向Delphi ASM中的XMM寄存器中的每个插槽广播一个8位值?

2 个答案:

答案 0 :(得分:4)

你的意思是你在XMM寄存器的LSB中有一个字节,并希望在该寄存器的所有通道中复制它?我不知道Delphi的内联汇编语法,但在Intel / MASM语法中,可以这样做:

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

答案 1 :(得分:3)

最快的选项是pshufb的SSSE3(如果可用)。

; 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 bw / wd更好 - > pshufd xmm0, xmm0, 0,因为有some CPUs with only 64-bit shuffle units. (Including Merom and K8)。在这样的CPU上,pshuflw速度很快,punpcklqdq也是如此,但pshufdpunpck的粒度小于64位的速度很慢。所以这个序列只使用一个"慢速洗牌"指令,bw / wd / pshufd为3。

在所有后来的CPU上,这两个3指令序列之间没有区别,因此在这种情况下调整旧CPU的成本并不高。有关指令表,另请参阅http://agner.org/optimize/

这是迈克尔回答的序列,中间两条指令被pshuflw取代。

如果您的字节在整数寄存器中,则可以使用乘以0x01010101将其广播为4个字节。 e.g。

; movzx   eax, whatever

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

movd   xmm0, eax
pshufd xmm0, xmm0, 0

请注意,imul的非直接源操作数可以是内存,但它必须是32位内存位置,并且您的字节零扩展为32位。

如果您的数据在内存中启动,首先加载到整数寄存器可能不值得。只需movd到xmm寄存器。 (或者可能pinsrb如果你需要避免更宽的负载以避免跨越页面或者可能是高速缓存行。但是这对于movd没有pmuludq的寄存器的旧值具有错误的依赖性。吨。)

如果指令吞吐量比延迟更重要,那么如果您不能使用pshufb,则值得考虑; low 32 bits of xmm0 = your byte, **zero extended** pmuludq xmm0, xmm7 ; xmm7 = 0x01010101 in the low 32 bits pshufd xmm0, xmm0, 0 ,即使它在大多数CPU上有5个周期延迟。 / p>

-2147483648