Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
向Delphi ASM中的所有16个XMM插槽广播一个字节值_Delphi_Assembly_Delphi 7_Sse_Basm - Fatal编程技术网

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

向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

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


如何在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来广播它…”-这很聪明。