我正在逐步学习SIMD编程,并且已经设计了一个(看似)简单的问题,希望我可以使用SIMD(目前只能访问AVX CPU)来加速使用SIMD。
我有一个由2^k
个字符(例如0
,1
,2
,3
)组成的长字符串,并且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'
。
阅读评论并玩转我已经实现了这些认识。我可以将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
如何在这里为我提供帮助,或者是否有更聪明的方法可以做到这一点。甚至这种“水平”方法都是愚蠢的,我必须重新考虑。
欢迎任何提示!