c - 使用 SSE 反转字符串

标签 c x86 sse simd

我们如何使用 SSE 反转字符串?这个概念对我来说是新的,所以请给我一些有关它的信息。原因是因为有人说使用 SSE 会加​​快代码和运行时的速度。

我搜索了 SSE,即 _mm128,但不知道如何分解它们。

谢谢

最佳答案

如果您可以假设至少为 SSSE3,那么使用 _mm_shuffle_epi8 就非常容易,但在执行此操作之前,您应该真正确保 (a) 您当前的实现是性能瓶颈,并且 (b)您已尽一切努力使当前实现尽可能快,因为这是一个如此简单的操作,对于任何像样的实现来说,其性能实际上应该仅受内存带宽的限制。

无论如何,这是一个简单的实现和测试工具:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <tmmintrin.h> // SSSE3

void reverse(char *begin, char *end)
{
    while (begin < end)
    {
        const char c = *begin;
        *begin = *end;
        *end = c;
        ++begin;
        --end;
    }
}

void vreverse(char *begin, char *end)
{
    const __m128i vrev = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);

    ssize_t len = end - begin + 1;

    while (len >= 16)
    {
        __m128i v1 = _mm_loadu_si128((__m128i *)begin);
        __m128i v2 = _mm_loadu_si128((__m128i *)(end - 15));
        v1 = _mm_shuffle_epi8(v1, vrev);
        v2 = _mm_shuffle_epi8(v2, vrev);
        _mm_storeu_si128((__m128i *)(end - 15), v1);
        _mm_storeu_si128((__m128i *)begin, v2);
        begin += 16;
        end -= 16;
        len -= 32;
    }
    if (len > 1)
    {
        reverse(begin, end);
    }
}

int main(void)
{
    const size_t MAX_LEN = 64;
    char s1[MAX_LEN + 1], s2[MAX_LEN + 1];
    size_t i, len;

    for (len = 0; len < MAX_LEN; ++len)
    {
        for (i = 0; i < len; ++i)
        {
            s1[i] = s2[i] = (char)('a' + rand() % 26);
        }
        s1[len] = s2[len] = '\0';
        reverse(s1, s1 + len - 1);
        vreverse(s2, s2 + len - 1);
        if (memcmp(s1, s2, len) != 0)
        {
            printf("FAIL: len = %zu\n", len);
            printf("FAIL: s1 = %s\n", s1);
            printf("FAIL: s2 = %s\n", s2);
        }
        else
        {
            //printf("PASS: len = %zu\n", len);
        }
    }
    return 0;
}

测试一下:

$ gcc -Wall -mssse3 -O3 vreverse.c && ./a.out
$

关于c - 使用 SSE 反转字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19627181/

相关文章:

c - 使用 Yacc 和 Lex 设计一个处理多种类型的计算器

c - 为什么我不能从 WriteConsole 重定向输出?

assembly - 为什么编译器在子程序之间插入 INT3 指令?

c++ - 中间指针的动态对齐(16 字节)

C - 1/n 数之和

c - 带空格的 Scanf 根本不读取

x86 汇编程序 : floating point compare

c++ - SSE/AVX 寄存器的非零字节索引

c++ - 对于单精度矩阵运算,AVX 与 SSE 的 Eigen 性能没有差异?