SIMD - простейшая задача
Что бы понять, как можно работать с SIMD пытаюсь сделать с его помощью простейшую и понятную для себя задачу, но SIMD оказался слишком отличным от абстрактного программируйся Си или С++.
Может кто нибудь натолкнет на мысль в "решении" такой задачки:
Пытаюсь реализовать поиск подстроки, хотя бы только из одного элемента в строке и взятие аресcа или номера элемента строки с которой найден искомый символ:
std::string my_string = "fhiihihijihihihjhihihihihihihihi"; //Ровно 32 байт, строка в которой нужно искать
std::string my_substring = "h"; //Искомая подстрока
std::string my_substring_16 = "hhhhhhhhhhhhhhhh"; //Это типа искомая подстрока, но для загрузки 16 байтовый регистр
Все на что меня хватило, это на вот это:
#include <iostream>
#include <string>
#include <vector>
#include <emmintrin.h>
#include <nmmintrin.h>
#include <immintrin.h>
int main()
{
std::string my_string = "fhiihihijihihihjhihihihihihihihi";
std::string my_substring = "h";
std::string my_substring_16 = "hhhhhhhhhhhhhhhh";
std::string kvazi_mask;
kvazi_mask.resize(16);
__m128i a = _mm_loadu_si128((__m128i*)&my_string[0]);
__m128i b = _mm_loadu_si128((__m128i*) & my_substring_16[0]);
__m128i my_compare = _mm_cmpeq_epi8(a, b); //То есть сравниваю два загруженных 16-байтовых регистра по каждому байту.
_mm_storeu_si128((__m128i*)& kvazi_mask[0], my_compare); //Переписываю результат из my_compare в kvazi_mask, чтобы посмотреть, что там получилось.
for (int i = 0; i < 16; i++)
{
std::cout<< (int)kvazi_mask[i] << std::endl;
}
}
//Получилось следующее:
0 -1 0 0 -1 0 -1 0 0 0 -1 0 -1 0 -1 0
То есть "0" - значит байты не равны, "-1" - значит равны.
И вот как мне теперь эти "-1" можно "преобразовать" в адреса или номера элементов строки my_string. И это только при том, что я взял для сравнения только первые 16 байт строки my_string.
И что то даже придумать ничего не могу.
В общем вот такое у меня получилось:
#include <iostream>
#include <string>
#include <vector>
#include <emmintrin.h>
#include <nmmintrin.h>
#include <immintrin.h>
__m128i a;
__m128i my_add_m128i_mask_substring_mask;
__m128i my_add_m128i_mask_ONE = _mm_set1_epi8(1); //Маска
char my_add_temp_massiv[16] = { 0 };
int my_find_SIMD(std::string& my_string, std::string& my_substring, std::vector<size_t>& number_vector_1D)
{
number_vector_1D.resize(0);
my_add_m128i_mask_substring_mask = _mm_set1_epi8(my_substring[0]); //Маска подсроки
size_t mysting_size = my_string.size() / 16;
size_t my_cntr = 0;
for (int i = 0; i < mysting_size; i++)
{
a = _mm_loadu_si128((__m128i*) & my_string[i*16]);
__m128i my_compare = _mm_cmpeq_epi8(my_add_m128i_mask_substring_mask, a);
__m128i my_add_m128i_summ = _mm_add_epi8(my_compare, my_add_m128i_mask_ONE);
_mm_storeu_si128((__m128i*)& my_add_temp_massiv[0], my_add_m128i_summ);
for (int y = 0; y < 16; y++)
{
if (my_add_temp_massiv[y] == 1)
{
my_cntr++;
}
else
{
number_vector_1D.push_back(my_cntr);
my_cntr++;
}
}
}
return 0;
}
И что интересно - это хоть и кривой код, но работает и пусть хоть в этом конкретном случае, но работает в 2.5 раза быстрее, чем strstr().