5

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

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

4

3 回答 3

5

迈克尔的回答会奏效。作为替代方案,如果您可以假设SSSE3指令集,那么使用Packed Shuffle Bytes pshufb也可以。

AL假设 (1) (例如)中的 8 位值和 (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 理解 SSSE3。

于 2015-09-19T21:58:05.517 回答
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
于 2015-01-05T13:38:35.200 回答
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因为有些 CPU 只有 64 位 shuffle 单元。(包括 Merom 和 K8)。在这样的 CPU 上,pshuflw速度很快,punpcklqdq但在小于 64 位的粒度下速度很慢pshufdpunpck所以这个序列只使用一个“slow shuffle”指令,而 bw / wd / pshufd 使用 3 个指令。

在所有后来的 CPU 上,这两个 3 指令序列之间没有区别,因此在这种情况下,我们无需为旧 CPU 进行任何调整。另请参阅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' 的非立即源操作数可以是内存,但它必须是 32 位内存位置,并且您的字节零扩展为 32 位。


如果您的数据从内存中开始,那么首先加载到整数寄存器中可能不值得。只是movd到一个 xmm 寄存器。(或者可能pinsrb如果您需要避免更广泛的负载以避免跨越页面或缓存行。但这对寄存器的旧值有错误的依赖性,而movd没有。)

如果指令吞吐量比延迟更重要,那么pmuludq如果您不能使用pshufb,则值得考虑,即使它在大多数 CPU 上都有 5 个周期延迟。

; low 32 bits of xmm0 = your byte, **zero extended**
pmuludq xmm0, xmm7        ; xmm7 = 0x01010101 in the low 32 bits
pshufd  xmm0, xmm0, 0
于 2017-11-09T05:47:31.143 回答