带有SIMD(和子字符串)的字符到位

时间:2018-12-11 16:19:52

标签: sse simd avx

我正在逐步学习SIMD编程,并且已经设计了一个(看似)简单的问题,希望我可以使用SIMD(目前只能访问AVX CPU)来加速使用SIMD。

我有一个由2^k个字符(例如0123)组成的长字符串,并且d想:

  • 生成给定长度substringlength的所有子字符串
  • 以位为单位转换所有子串

子字符串只是输入字符串中的字符序列:

012301230123012301230123012301233012301301230123123213012301230 

substringlength = 6;

string    bits
------+--+-----------------
012301 -> 01 00 11 10 01 00
123012 -> 10 01 00 11 10 01
230123 -> 11 10 01 00 11 10
301230 -> 00 11 10 01 00 11
...

我的问题是由于我对SIMD缺乏经验(我只读过Kusswurm撰写的“现代x86汇编语言编程”):

  

这是SIMD可以帮助的任务吗?

编辑:为简单起见,我们假设k = 2,因此ASCII码将仅为'0'..'3'

迭代1

阅读评论并玩转我已经实现了这些认识。我可以将ASCII转换为值,并按照建议将相邻的字节相乘:

        // SIMD 128-bit registers, apparently I cannot use AVX ones directly (some operations are AVX2 or AVX-512)
        __m128i sse, val, adj, res;
        auto mask = _mm_set_epi8(1, 1<<4, 1, 1<<4, 1, 1<<4, 1, 1<<4, 1, 1<<4, 1, 1<<4, 1, 1<<4, 1, 1<<4);
        auto zero = _mm_set_epi8('0', '0', '0', '0', '0', '0', '0', '0',
                                 '0', '0', '0', '0', '0', '0', '0', '0');

        // Load ascii values
        sse = _mm_loadu_si128((__m128i*) s.data());

        // Convert to integer values
        val = _mm_sub_epi8(sse[0], zero);

        // Multiply with mask byte by byte (aka SHL second bytes of val) and sum
        adj = _mm_maddubs_epi16(val, mask);

这里给出了一个对像我这样学习的人的作用的想法(我将需要更多的128位来编码一个子字符串, ascii以十六进制显示):

bytes   15   14   13   12   11   10    9    8    7    6    5    4    3    2    1    0

ascii   30   31   30   31   30   31   30   31   30   31   30   31   30   31   30   31

_mm_sub_epi8:

value    0    1    0    1    0    1    0    1    0    1    0    1    0    1    0    1

_mm_maddubs_epi16:

value    0    1    0    1    0    1    0    1    0    1    0    1    0    1    0    1
         *    *    *    *    *    *    *    *    *    *    *    *    *    *    *    *
mask     1    4    1    4    1    4    1    4    1    4    1    4    1    4    1    4
            +         +         +         +         +         +         +         +
        |        |         |         |         |         |         |         |        |
(16-bits)
bits     ....0100  ....0100  ....0100  ....0100  ....0100  ....0100  ....0100 ....0100

换句话说,前4位正确,编码了2个ascii字符,如果我理解正确_mm_maddubs_epi16对我的值的作用就是完全不确定!

现在,我需要某种相邻字节的“ shift-or ”,例如_mm_maddubs_epi16,它向左移第一个,而OR与第二个自变量一起,产生8位或16位值:

(16-bits)
bits     ....0100  ....0100  ....0100  ....0100  ....0100  ....0100  ....0100 ....0100
         | shl 4          |  | shl 4          |  | shl 4          |  | shl 4         |
         0100....  ....0100  0100....  ....0100  0100....  ....0100  0100.... ....0100
                 OR                 OR                  OR                  OR
             ....01000100      ....01000100         ....01000100       ....01000100

但是,我看不到_mm_bslli_si128如何在这里为我提供帮助,或者是否有更聪明的方法可以做到这一点。甚至这种“水平”方法都是愚蠢的,我必须重新考虑。

欢迎任何提示!

0 个答案:

没有答案