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().


Ответы (0 шт):