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