Assembly 将XMM寄存器设置为重复字节模式(广播常量字节)

Assembly 将XMM寄存器设置为重复字节模式(广播常量字节),assembly,sse,micro-optimization,sse2,Assembly,Sse,Micro Optimization,Sse2,我知道我们可以这样做,将字符移动到xmm寄存器: movaps xmm1, xword [.__0x20] align 16 .__0x20 db 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20 但由于这是一个记忆过程,我想知道是否有更好的方法?(另外,我说的是SSE2而不是其他SIMD类型…) 我希望xmm1寄存器的每个字节都是0x20,而不仅仅是一个字节。 (编者按:这可以称为

我知道我们可以这样做,将字符移动到xmm寄存器:

movaps xmm1, xword [.__0x20]

align 16
.__0x20 db 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20
但由于这是一个记忆过程,我想知道是否有更好的方法?(另外,我说的是SSE2而不是其他SIMD类型…)

我希望xmm1寄存器的每个字节都是0x20,而不仅仅是一个字节。

(编者按:这可以称为广播或splat。

这是
\u mm\u set1\u epi8(0x20)
固有的功能。

只有SSE2,从内存加载完整模式通常是最好的选择

在NASM源代码中,您可以使用
乘以16 db 0x20
,以便于维护


使用SSE3,您可以使用进行8字节广播加载。使用AVX,您可以使用进行4字节的广播加载这些广播加载在现代CPU上非常好,只在加载端口上运行,不需要随机uop。也就是说,它们与支持它们的CPU上的
movap
一样便宜,除了一个字节或两个以上的代码大小。与YMM寄存器的vbroadcastf128相同

大多数编译器似乎没有意识到这一点,并且会通过
\u mm_set1
进行常量传播,即使这样会产生一个32字节的常量而不是4字节的常量,即使只是
mov…
在循环之前加载它,而不是将它折叠到ALU指令的内存操作数中。(当AVX512可用时,广播加载仍然是可能的。)Clang有时会利用广播加载来实现简单常量

AVX2添加了
VPB/w/d/q
,但只有dword和qword是纯加载UOP。字节和字广播加载需要一个ALU shuffle uop,因此对于常量字节模式,您可能只希望广播加载一个重复字节4次的dword。(除非它是大查找表中的元素,否则使用字节或字广播加载或
pmovsx
符号扩展加载或其他方式压缩该表)

AVX512的添加使您可以
mov eax,0x202020
/
vpbroadcasted xmm0,eax
,如果您有AVX512VL


对于SSE2,至少需要2条指令,包括ALU洗牌,就像这样,可能不值得这么做

    movd    xmm0, [const_4B]
    pshufd  xmm0, xmm0, 0

一些重复常量可以在一对指令中动态生成,从
pcmpeqd xmm0、xmm0
中的所有常量开始。请参阅和Agner Fog的指南

这种模式似乎不容易生成。这是一种字节模式(不是word、dword或qword),SSE移位最多只能用于字粒度。但是,如果我们知道跨字节边界移位的位是0,则可以。e、 g

   pcmpeqd  xmm0, xmm0     ; set1( -1 )
   pabsb    xmm0, xmm0     ; set1_epi8(1)    SSSE3
   pslld    xmm0, 5        ; set1_epi8(1<<5)

; or with only SSE2, something even less efficient like shift / packsswb / shift
pcmpeqd-xmm0,xmm0;set1(-1)
pabsb xmm0,xmm0;set1_epi8(1)SSSE3

pslldxmm0,5;set1_epi8(1当所需字节为常量时,您所做的是最快的方法。我只是在寻找更好的方法(如果有)一些即时或(从寄存器)方式!您的字节是常量还是变量?如果它是常量,那么您所做的已经是最快的方式。在这种情况下,您的代码已经是理想的。根据您使用的汇编器,可能会有某种
times
dup
指令,使其更易于键入。您还可以定义宏如果这让你恼火。你知道GP 64位寄存器这个问题的任何答案吗?@Noah:对于常量,通常只是
mov rdi,0x0101010101
或其他什么。对于非常量,
imul rcx,rdi
,带有0x01重复常量,零后将字节扩展到rcx。因此
mov reg,imm64的最坏情况成本是
对于乘法器,
movzx ecx,byte source
imul r64,r64
。啊,比移位法聪明多了!@Noah:是的,快速硬件乘法器可以被“滥用”来做很多整洁的事情,包括将足够小的元素求和到高字节。()。乘法是一种移位和加法操作,加上或不受其他值位的控制。此外@phuclv还很好地解释了中的机制