使用 sse 内在函数时如何打破循环?

Posted

技术标签:

【中文标题】使用 sse 内在函数时如何打破循环?【英文标题】:how to break from a loop when using sse intrinsics? 【发布时间】:2013-01-25 14:17:51 【问题描述】:
__m128* pSrc1 = (__m128*) string;
__m128 m0 = _mm_set_ps1(0);    //null character

while(1)

    __m128 result = __m128 _mm_cmpeq_ss(*pSrc1, m0);

    //if character is \0 then break

    //do some stuff here

    pSrc1++;

我有一个长度可以是 16 的倍数的字符串。 如果 _mm_cmpeq_ss 返回相等,如何跳出循环?

【问题讨论】:

任何你不能做诸如 while(__m128 result != '\0') 之类的事情的原因 原谅我的无知,浮点运算不是 128 位 XMM 寄存器吗? @CHill60 因为您无法将 128 位向量与 char 进行相等性比较 @legends2k 不。XMM 寄存器上有许多整数运算,例如长度为 8、16、32 和 64 位的整数类型的按位和/或/加/子/多/掩码。跨度> @hirschhornsalz ...哎呀,当然羞愧地垂头丧气 【参考方案1】:

如果您在第一次遇到\0 时尝试跳出循环,那么您需要执行以下操作:

__m128i* pSrc1 = (__m128i *)string;         // init pointer to start of string
__m128i m0 = _mm_set1_epi8(0);              // vector of 16 `\0` characters

while (1)

    __m128i v0 = _mm_loadu_si128(pSrc1);    // get 16 chars from string
    __m128i v1 = _mm_cmpeq_epi8(v0, m0);    // compare all 16 chars with '\0'
    int vmask = _mm_movemask_epi8(v1);      // get 16 comparison result bits
    if (vmask != 0)                         // if any bit is 1
        break;                              // we found a `\0`, break out of loop
    pSrc1++;                                // next 16 characters...

如果您只想测试特定位置的\0 字符而忽略其他任何字符,则可以将if (vmask != 0) 测试更改为符合您特定要求的内容。

【讨论】:

只有 m 17th, 33rd ...字符可以是 \0 即我的字符串长度总是 16 的倍数 OK - 这个解决方案仍然有效(除非您想在其他地方忽略 \0 字符?)。无论如何,我已经更新了答案以涵盖这种可能性。 movemask 是否优于 ptest xmm,same,以测试全零? (当然,如果您已经在使用其他 SSE4.1 指令。)test / jcc 可以进行宏融合,因此它的 uops 数量相同(movemask + test&branch vs. ptest + branch),但指令更少。 movemask 在 Haswell 上有 3 个周期延迟(在 SnB/IvB 上有 2 个),而 ptest 即使在 Haswell 上也只有 2 个周期延迟。 movmsk 只能在 p0 上运行,而 ptest 可以在 p0/p5 (Haswell) 上运行,因此它使两个 FMA 端口都空闲。我认为在大多数情况下,PTEST 会是更好的选择。 哎呀,nvm,PTEST 在 Haswell 上是 2 微秒。因此,如果 uop 吞吐量是瓶颈,它可能比movmsk + test 慢。我想它仅在仅测试高位还不够的情况下才有用,或者您可以将它与 2 个不同的操作数一起使用(以获得免费的按位与)。根据 Agner Fog 的表格,PTEST 是 SnB 上的 1 个融合域 uop,但对于执行端口仍然是 2 个未融合的 uop。在 IvB/HSW 上,即使在融合域中也是 2 微秒。

以上是关于使用 sse 内在函数时如何打破循环?的主要内容,如果未能解决你的问题,请参考以下文章

了解 SSE 的内在函数如何使用内存

如何将此代码重写为 sse 内在函数

如何将参数传递给英特尔 SSE 内在函数中的 const 值?

修改函数以使用 SSE 内在函数

在 Visual C++ 中删除 SSE2 内在函数

用 sse 执行内在函数