如何从另一个XMM寄存器条目中获取4个相同的浮点数并将其填充到x86 XMM寄存器中?

12

我正在尝试在C/C++代码中实现一些内联汇编,以利用SSE。我想复制和复制值(从XMM寄存器或存储器)到另一个XMM寄存器。例如,假设我有一些值{1, 2, 3, 4}在存储器中。我想将这些值复制,使得xmm1被填充为{1, 1, 1, 1},xmm2为{2, 2, 2, 2},等等。

查阅英特尔参考手册,我没有找到可用于此的指令。我是否只需要使用重复的MOVSS和旋转(通过PSHUFD)的组合?

3个回答

16

有两种方法:

  1. 仅使用 shufps

  2. __m128 first = ...;
    __m128 xxxx = _mm_shuffle_ps(first, first, 0x00); // _MM_SHUFFLE(0, 0, 0, 0)
    __m128 yyyy = _mm_shuffle_ps(first, first, 0x55); // _MM_SHUFFLE(1, 1, 1, 1)
    __m128 zzzz = _mm_shuffle_ps(first, first, 0xAA); // _MM_SHUFFLE(2, 2, 2, 2)
    __m128 wwww = _mm_shuffle_ps(first, first, 0xFF); // _MM_SHUFFLE(3, 3, 3, 3)
    
    让编译器使用_mm_set1_ps_mm_cvtss_f32来选择最佳方法:
    __m128 first = ...;
    __m128 xxxx = _mm_set1_ps(_mm_cvtss_f32(first));
    

请注意,第二种方法在MSVC上会产生可怕的代码,如此讨论,并且只会产生'xxxx'作为结果,不像第一种选项。

我正在尝试在C/C++代码中实现一些内联汇编以利用SSE。

这是高度不可移植的。使用内置函数。


关于可移植性,那是非常好的一点。由于这主要是我自己的学习练习,所以我并没有真正考虑过它。你的文章一开始看起来也非常有趣。我期待着花更多的时间去阅读它。 - jbl
1
这个答案中展示的内置方法比内联汇编更好,因为内置函数允许编译器进行更多的优化,而这些优化在内联汇编中不会被执行:寄存器分配、循环展开、指令交错、将不变量提取出循环等。我的答案是使用汇编语言,因为原始问题就是这样要求的,但如果我要自己使用这段代码,我会使用内置函数来实现性能和可移植性的平衡。 - Adisak
Adisak:你说的对,除了MSVC以外,其他编译器都能很好地处理内嵌函数(请看我的文章)。在MSVC中,如果性能比可移植性和可维护性更重要的话(很少情况下),手写汇编会更好。不过我建议还是换个编译器吧:) - LiraNuna
至少在Intrinsics方面有优化的潜力。听到MSVC实现得不好真是令人沮丧。希望这个问题能在不久的将来得到解决,针对VS2010进行改进。 - Adisak
好的,它并没有。与VC2008相同的结果(至少目前是这样)。 - LiraNuna
使用SSE2中的_mm_shuffle_epi32是否合适?如果我理解底层汇编指令正确,_mm_shuffle_epi32将节省一次移动操作(目标寄存器被填充而不触及源寄存器,因此无需进行预备复制)。http://msdn.microsoft.com/en-us/library/56f67xbk%28v=vs.90%29.aspx - Antonio

6

将源寄存器移动到目标寄存器。使用“shufps”,只需两次使用新的目标寄存器,然后选择适当的掩码。

下面的示例将XMM2.x的值广播到XMM0.xyzw

MOVAPS XMM0, XMM2
SHUFPS XMM0, XMM0, 0x00

2

如果您的值在内存中是16字节对齐的:

movdqa    (mem),    %xmm1
pshufd    $0xff,    %xmm1,    %xmm4
pshufd    $0xaa,    %xmm1,    %xmm3
pshufd    $0x55,    %xmm1,    %xmm2
pshufd    $0x00,    %xmm1,    %xmm1

如果不行,您可以进行非对齐加载,或者进行四个标量加载。在较新的平台上,非对齐加载应该更快;在旧平台上,标量加载可能会更快。

正如其他人所指出的那样,您还可以使用shufps


注意:pshufd是SSE2指令。 - LiraNuna
@LiraNuna:我认为提问者所说的“SSE”是指SSE、SSE2、SSE3、SSSE3、SSE4.1、SSE4.2等未明确指定的子集。由于几乎所有的x86硬件现在都支持SSE2,已经有相当多年了,因此可以安全地假设提问者并不想禁用它。 - Stephen Canon
这只是一般性的注释 - 它并不针对你的回答。 - LiraNuna

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接