Sse 使用SIMD(和子字符串)将字符转换为位

Sse 使用SIMD(和子字符串)将字符转换为位,sse,simd,avx,Sse,Simd,Avx,我正在一点一点地学习SIMD编程,我设计了一个(似乎)简单的问题,我希望我能使用SIMD加速(AVX,目前我只能访问AVX CPU) 我有一个由2^k字符组成的长字符串(例如0,1,2,3),我想: 生成给定长度的所有子字符串substringlength 将所有子字符串转换为位 子字符串只是输入字符串中的字符序列: 012301230123012301230123012301233012301301230123123213012301230 substringlength = 6;

我正在一点一点地学习SIMD编程,我设计了一个(似乎)简单的问题,我希望我能使用SIMD加速(AVX,目前我只能访问AVX CPU)

我有一个由
2^k
字符组成的长字符串(例如
0
1
2
3
),我想:

  • 生成给定长度的所有子字符串
    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缺乏经验(我只读过Kussworm的“现代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);
换句话说前4位是正确的,编码了2个ascii字符,如果我理解正确我的值被
\u mm\u maddubs\u epi16
改变了,我一点也不确定

现在我需要对相邻字节进行某种“移位或”,类似于将第一个字节向左移位的
\u mm\u maddubs\u 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
然而,我看不出
\u mm\u bslli\u si128
在这方面如何帮助我,或者是否有更聪明的方法来做到这一点。也许甚至这种“横向”的方法也很愚蠢,我不得不重新思考


欢迎任何提示

您是否需要一个(ASCII?)字符字符串的中间步骤,或者您真的只想生成打包在一起的所有k位块的排列?或者等等,您不是在生成这些子字符串,而是从给定的输入字符串中提取它们,就像使用滑动窗口一样?您可能需要为每个可能的
k
使用不同的代码来高效地执行此操作,通过自定义混洗和位移位计数跨字节将位打包在一起
pmaddubsw
的向量为
{1,1对于
k=8
[p]aligner
在循环中应该是有用的。@PeterCordes我只是通过使用
k=2
并添加一些代码来编辑问题。不过,我怀疑它是否能按我的意图工作。你想要
mask=4=1吗
(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