向Delphi ASM中的所有16个XMM插槽广播一个字节值
在AVX中,使用VBROADCASTS命令,或者在SSE中,如果值是双精度或浮点值,则这很容易实现向Delphi ASM中的所有16个XMM插槽广播一个字节值,delphi,assembly,delphi-7,sse,basm,Delphi,Assembly,Delphi 7,Sse,Basm,在AVX中,使用VBROADCASTS命令,或者在SSE中,如果值是双精度或浮点值,则这很容易实现 如何在Delphi ASM中向XMM寄存器中的每个插槽广播单个8位值?您的意思是在XMM寄存器的LSB中有一个字节,并希望在该寄存器的所有通道上复制它?我不知道Delphi的内联汇编语法,但在Intel/MASM语法中,可以这样做: punpcklbw xmm0,xmm0 ; xxxxxxxxABCDEFGH -> xxxxxxxxEEFFGGHH punpcklwd xmm0,xmm
如何在Delphi ASM中向XMM寄存器中的每个插槽广播单个8位值?您的意思是在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
迈克尔的答案会有用的。作为替代方案,如果您可以假设
SSSE3
指令集,那么使用压缩无序字节也可以
假设(1)在AL
(例如)中有一个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。最快的选项是SSSE3 for
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 bw/wd->pshufd xmm0,xmm0,0更好,因为有。在这样的CPU上,pshuflw
是快的,punpcklqdq
也是快的,但是粒度小于64位的pshufd
和punpck
是慢的。因此,这个序列只使用一条“慢洗牌”指令,而bw/wd/pshufd则使用3条
在所有后来的CPU上,这两个3指令序列之间没有区别,因此在这种情况下,为旧CPU进行调优不需要花费任何成本。有关说明表,请参见
这是Michael答案的顺序,中间的两条指令替换为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
没有。)
如果指令吞吐量比延迟更重要,那么如果不能使用pshufb
,则值得考虑pmuludq
,即使它在大多数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
是的,就是这个想法。如何将初始字节加载到LSB中?我发现的引用再次指向浮点。MOVD
指令允许您将32位寄存器或内存位置的内容移动到xmm
寄存器中。我假设最后一条指令应该是“punpcklqdq”:)一旦到达dword元素,您就可以pshufd xmm0,xmm0,0
。或者更好:punpcklbw
/pshuflw
/punpcklqdq
(在Merom/K8上更快,在pshufd
和其他粒度小于64位的128b随机洗牌更慢时更快)。哇,你肯定知道你的SSE。有一个问题:pinsrb将如何每个跨页?@IamIC:不会,这就是为什么你会使用它而不是movd
将一个字节放入xmm寄存器的低位字节。“…乘以0x01010101来广播它…”-这很聪明。