【问题标题】:How do you populate an x86 XMM register with 4 identical floats from another XMM register entry?如何使用来自另一个 XMM 寄存器条目的 4 个相同浮点数填充 x86 XMM 寄存器?
【发布时间】:2011-01-02 05:03:30
【问题描述】:

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

查看英特尔参考手册,我找不到执行此操作的说明。我只需要结合使用重复的 MOVSS 和旋转(通过 PSHUFD 吗?)?

【问题讨论】:

    标签: c++ c x86 inline-assembly sse


    【解决方案1】:

    有两种方式:

    1. 仅使用shufps

      __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)
      
    2. 让编译器选择使用_mm_set1_ps_mm_cvtss_f32的最佳方式:

      __m128 first = ...;
      __m128 xxxx = _mm_set1_ps(_mm_cvtss_f32(first));
      

    请注意,第二种方法会在 MSVC 上产生可怕的代码as discussed here,并且只会产生 'xxxx' 作为结果,这与第一种方法不同。

    我正在尝试实现一些内联 汇编程序(在 C/C++ 代码中) 上证所的优势

    这是非常不便携的。使用内在函数。

    【讨论】:

    • 关于可移植性的观点非常好。我没有真正想到它,因为这对我来说主要是一个学习练习。乍一看,您的文章也很有趣。我期待着花更多时间在它上面。
    • 这个答案中显示的内在方法比内联 asm 更好,因为内在方法允许编译器进行更多内联 asm 没有执行的优化:寄存器分配、循环展开、指令交错、提升不变量循环等。我的答案是 ASM,因为这是最初的问题所要求的,但如果我要自己使用代码,我会用 Intrinsics 编写它以提高性能可移植性。
    • Adisak:你所说的对除 MSVC 之外的任何东西都是正确的——它对内在函数的处理非常糟糕(请参阅我的文章)。在 MSVC 中,如果性能优先于可移植性和可维护性(很少),则手写汇编会更好。我只是建议切换编译器:)。
    • 好吧,至少 Intrinsics 有优化的潜力。听到 MSVC 对它们的实施很糟糕,这很令人难过。希望这将在不久的将来为 VS2010 解决。
    • 嗯,它没有。结果与 VC2008 相同(至少目前如此)。
    【解决方案2】:

    将源移动到目标寄存器。使用 'shufps' 并使用新的 dest 寄存器两次,然后选择适当的掩码。

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

    MOVAPS XMM0, XMM2
    SHUFPS XMM0, XMM0, 0x00
    

    【讨论】:

      【解决方案3】:

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

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

      如果没有,您可以执行未对齐加载或四个标量加载。在较新的平台上,未对齐的负载应该更快;在旧平台上,标量负载可能会胜出。

      正如其他人所说,您也可以使用shufps

      【讨论】:

      • 注意:pshufd 是 SSE2 指令。
      • @LiraNuna:我认为提问者使用“SSE”来表示 SSE、SSE2、SSE3、SSSE3、SSE4.1、SSE4.2 等的一些未指定子集。因为基本上所有 x86 硬件都有SSE2 支持已经有好几年了,假设提问者并不是有意禁止它似乎很安全。
      • 这是一个一般性说明 - 它并非旨在以任何方式反对您的回答。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-16
      • 2011-01-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多