【问题标题】:SSE instruction to sum 32 bit integers to 64 bitSSE 指令将 32 位整数加到 64 位
【发布时间】:2015-11-12 00:41:07
【问题描述】:

我正在寻找一条 SSE 指令,它在 __m128i 中接受四个 32 位整数的两个参数,计算相应对的总和并将结果作为 __m128i 中的两个 64 位整数返回。

有这方面的说明吗?

【问题讨论】:

标签: sse simd


【解决方案1】:

没有带有进位的 SSE 操作。这样做的方法是首先使用全零辅助向量将 32 位整数 (punpckldq/punpckhdq) 解压缩为 4 组 64 位整数,然后使用 64 位成对加法。 /p>

【讨论】:

  • SSE4.1 有一些整数扩展指令,使这更容易和更快。
  • @Mysticial:对于有符号整数,使用pmovsx 实际上很多更容易和更快。它并没有我一开始想的那么大,因为我在写我的解包问题的答案时有一个很好的主意,而不是解包并然后混合一个标志掩码。但是pmovsx 如果你从内存中加载是非常好的,否则你必须努力让上半部分转移到准备符号扩展它。
【解决方案2】:

SSE 仅对 byte->word 和 word->dword 具有此功能。 (pmaddubsw (SSSE3) 和 pmaddwd (MMX/SSE2),垂直相乘 v1 * v2,然后水平相加相邻对。)

我不清楚您希望输出是什么。您有 8 个输入整数(两个 4 向量)和 2 个输出整数(一个两个向量)。由于没有任何类型的 32+32 -> 64b 向量加法的 insn,让我们看看如何将向量的低两个 32b 元素零扩展或符号扩展为 64b。你可以将它组合成你需要的任何东西,但请记住,没有添加水平对phaddq,只有垂直paddq

phaddd 与您想要的类似,但没有加宽:结果的下半部分是第一个操作数中水平对的总和,高半部分是第二个操作数中水平对的总和。如果您需要所有这些结果,并且您不会进一步组合它们,那么它几乎只值得使用。 (即,通常更快地随机和垂直添加,而不是运行phadd 在减少结束时对向量累加器进行水平求和。如果您要将所有内容求和为一个结果,请进行正常的垂直求和,直到您重新减少到一个寄存器。)phaddd 可以在硬件中实现与paddd 一样快(单周期延迟和吞吐量),但它不在任何 AMD 或 Intel CPU 中。


就像 Mysticial 评论的那样,SSE4.1 pmovzxdq / pmovsxdq 正是您所需要的,甚至可以作为从 64b 内存位置(包含两个 32b 整数)加载的一部分即时执行。

SSE4.1 是在 Nehalem 之前的一代 Intel Penryn 中引入的,第二代 Core2(45nm 芯片收缩核心 2)。在比这更早的 CPU 上回退到非向量代码路径可能没问题,这取决于您对在已经老旧且速度较慢的 CPU 上不慢的关心程度。


没有 SSE4.1:

无符号零扩展很容易。就像 pmdj 回答的那样,只需使用 punpck* lo 和 hi 以零解压。

如果您的整数是有符号的,您必须手动进行符号扩展。

没有psraq,只有psrad(压缩右移算术双字)和psraw。如果有,您可以自行解包,然后算术右移 32b。

相反,我们可能需要生成一个向量,其中每个元素都转换为其符号位。然后将其与未打包的向量混合(但 pblendw 也是 SSE4.1,所以我们必须使用 por)。

或者更好的是,用符号掩码向量解包原始向量。

# input in xmm0
movdqa    xmm1, xmm0
movdqa    xmm2, xmm0
psrad     xmm0, 31     ; xmm0 = all-ones or all-zeros depending on sign of input elements.  xmm1=orig ; xmm2=orig
                       ; xmm0 = signmask;  xmm1=orig  ; xmm2=orig
punpckldq xmm1, xmm0   ; xmm1 = sign-extend(lo64(orig))
punpckhdq xmm2, xmm0   ; xmm2 = sign-extend(hi64(orig))

对于英特尔 SnB 或 IvB 上的两个结果,这应该以 2 个周期延迟运行。 Haswell 和以后只有一个 shuffle 端口(所以他们不能同时执行 punpck insns ),所以 xmm2 将在那里延迟另一个周期。 Pre-SnB Intel CPU 通常在前端(解码器等)上遇到向量指令的瓶颈,因为它们通常平均每个 insn 超过 4B。

对于没有移动消除的 CPU(在寄存器重命名阶段处理 mov 指令,因此它们是零延迟。仅英特尔,并且仅适用于 IvB 及更高版本。)使用 3 操作数 AVX 指令,您不需要 movdqa 或第 3 个寄存器,但无论如何您都可以将 vpmovsx 用于 low64。要对高位 64 进行符号扩展,您可能需要将 psrldq 字节移位高位 64 到低位 64。

movhlpspunpckhqdq self,self 使用更短的编码指令。 (或 AVX2 vpmovsx 到 256b reg,然后 vextracti128 上 128,只需两条指令即可获得 128b 结果。)


与 GP 寄存器移位(例如 sar eax, 31)不同,向量移位使计数饱和而不是屏蔽。将原始符号位保留为 LSB(移位 31)而不是它的副本(移位 32)也可以正常工作。它的优点是不需要在代码中添加大注释来解释这一点,以便人们看到psrad xmm0, 32 时会担心。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-11-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多