【问题标题】:SSE multiplication of 4 32-bit integers4 个 32 位整数的 SSE 乘法
【发布时间】:2012-05-17 01:31:54
【问题描述】:

如何将四个 32 位整数乘以另外 4 个整数? 我没有找到任何可以做到这一点的指令。

【问题讨论】:

    标签: x86 sse simd multiplication sse2


    【解决方案1】:

    PMULLD,来自 SSE 4.1,就是这样做的。

    描述有点误导,它谈到有符号乘法,但由于它只存储低 32 位,所以它确实是一个符号忽略指令,你可以同时使用它,就像 IMUL

    【讨论】:

    • 谢谢。但是有没有办法只使用 SSE 2 指令?
    • _mm_mullo_epi32 如果您更愿意使用内部函数而不是原始程序集
    • @Leviathan 是的,但您需要一些说明。根据架构,四个imul 可能更快更简单
    • 为什么只有 SSE2 ?你真的需要支持超过 10 年的 CPU 吗?
    • @PaulR 仍然有很多 AMD。只有 Bulldozer 支持 SSSE3 及更高版本。
    【解决方案2】:

    如果您需要有符号 32x32 位整数乘法,那么software.intel.com 的以下示例看起来应该可以满足您的需求:

    static inline __m128i muly(const __m128i &a, const __m128i &b)
    {
        __m128i tmp1 = _mm_mul_epu32(a,b); /* mul 2,0*/
        __m128i tmp2 = _mm_mul_epu32( _mm_srli_si128(a,4), _mm_srli_si128(b,4)); /* mul 3,1 */
        return _mm_unpacklo_epi32(_mm_shuffle_epi32(tmp1, _MM_SHUFFLE (0,0,2,0)), _mm_shuffle_epi32(tmp2, _MM_SHUFFLE (0,0,2,0))); /* shuffle results to [63..0] and pack */
    }
    

    您可能希望有两个构建 - 一个用于旧 CPU,一个用于最近的 CPU,在这种情况下,您可以执行以下操作:

    static inline __m128i muly(const __m128i &a, const __m128i &b)
    {
    #ifdef __SSE4_1__  // modern CPU - use SSE 4.1
        return _mm_mullo_epi32(a, b);
    #else               // old CPU - use SSE 2
        __m128i tmp1 = _mm_mul_epu32(a,b); /* mul 2,0*/
        __m128i tmp2 = _mm_mul_epu32( _mm_srli_si128(a,4), _mm_srli_si128(b,4)); /* mul 3,1 */
        return _mm_unpacklo_epi32(_mm_shuffle_epi32(tmp1, _MM_SHUFFLE (0,0,2,0)), _mm_shuffle_epi32(tmp2, _MM_SHUFFLE (0,0,2,0))); /* shuffle results to [63..0] and pack */
    #endif
    }
    

    【讨论】:

    • 好答案。有趣的是,您在代码中犯了与我曾经在代码中完全相同的错字:应该是_____SSE4_1_____(E 和 4 之间没有下划线)。烦人,因为您不会轻易注意到它 - 只要备用代码路径正常,程序就可以完美运行
    • @drhirsch:感谢您修复该问题 - 在实际代码中,我倾向于使用 __MNI____SNI__ 等 - 主要是出于历史原因,但它也不太容易出现上述简单错误.
    • 太棒了,谢谢!现在,如果有一个类似的技巧可以在仅使用 SSE2 的 CPU 上替换 _mm_insert_epi32...
    • 请注意,“旧 CPU 路径”实际上可能比在 4 个整数上的显式 for 循环要慢 - 在我的机器上肯定不会更快。
    猜你喜欢
    • 2015-07-29
    • 2013-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-06
    • 2012-03-16
    • 2019-08-18
    相关资源
    最近更新 更多