我知道我们可以做这样的事情来将字符移动到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,而不只是一个字节..
仅使用SSE2,通常最好从内存中加载完整模式。
使用SSE3,您可以使用movddup
进行8字节广播加载。使用AVX,您可以使用movddup
进行4字节的广播加载。 这些广播负载在现代CPU上非常好,可以在just负载端口上运行,不需要随机播放。即,它们与支持它们的CPU上的vbroadcastss
一样便宜一个或两个以上的代码大小。 vbroadcastss
到YMM寄存器相同。
[大多数编译器似乎都没有意识到这一点,即使通过movaps
导致32字节常量而不是4字节,也将通过vbroadcastf128
进行常量传播,即使_mm_set1
在循环之前加载它而不折叠将其放入ALU指令的内存操作数中。 (并且当AVX512可用时,仍然可以通过广播加载来实现。)Clang有时确实利用广播加载来获取简单的常量。
[AVX2加mov...
,但是只有dword和qword是纯负载uops。字节和字的广播加载需要ALU shuffle uop,因此对于恒定字节模式,您可能只想广播加载重复4个字节的dword。 (除非它是来自大查找表的元素,然后使用字节或字广播负载或vpbroadcastb/w/d/q
符号扩展负载或其他方式压缩表)。
[AVX512添加pmovsx
,因此如果具有AVX512VL,则可以vpbroadcastb/w/d/e
from an integer register / vpbroadcastb/w/d/e
。
对于SSE2,这样至少需要2条指令,包括ALU随机播放,可能不值得。
mov eax, 0x20202020
可以从一对
vpbroadcastd xmm0, eax
的全1开始,通过几个指令快速生成一些重复常数。请参阅movd xmm0, [const_4B] pshufd xmm0, xmm0, 0
和Agner Fog的指南。
此模式确实不是
似乎易于生成。这是一种字节模式(不是word,dword或qword),并且SSE移位最多只能使用单词粒度。但是,如果我们知道跨字节边界移位的位为0,就可以了。例如pcmpeqd xmm0,xmm0
这不太可能值得,除非您确实想避免该常量发生缓存丢失的可能性。平均而言,通常会提前产生负载。