SSE از اونجایی که عملیات هایی که انجام میده بر خلاف حالت عادی روی register های 128 بیتی انجام میشه(رجیستر های XMM) شما اول باید 128 بیت از 2 وکتور جدا کنید و داخل union ای که ذکر کردید قرار بدید (برای هر وکتور یک آنیون )بعد این 2 تا آنیون رو با توابعی که هست یا مستقیما با اسمبلی جمع بزنید و در نهایت آنیونی که نتیجه جمع 2 وکتور هست رو به وکتور سوم انتقال بدیم .
برای انجام چیزایی که گفتم بترتیب این کارها باید انجام بشن :
اول دیتا هر 2 تا وکتور ورودی که از نوع int* هست رو به __m128i* تبدیل می کنید :
std::vector<int> a,b;
__m128i* src= reinterpret_cast<__m128i*>(a.data());
__m128i* src2= reinterpret_cast<__m128i*>(b.data());
حالا برای load کردن دیتا از وکتور به آنیون __mm128i از یکی از این 3 تابع استفاده می کنیم :
//khoondan 128 bit az p
//hatman bayad p 16bit align bashe
extern __m128i _mm_load_si128(__m128i const*_P);
//khoondan 128bit az p
//niayze be align boodan nist
extern __m128i _mm_loadu_si128(__m128i const*_P);
//64bit az p mikhoone va 64bit aval register mmx ro set mikone 64bit badi ro 0 mizare
extern __m128i _mm_loadl_epi64(__m128i const*_P);//l mokhafaf low hast(low quad word)
مثال :
std::vector<int> a={1,2,3,4};
__m128i* src= reinterpret_cast<__m128i*>(a.data());
__m128i var=_mm_load_si128(src);//var alan shamele 1,2,3,4 hast
کار بالا رو برای src2 هم انجام میدیم
برای جمع زدن 2 تا __mm128i از یکی از این توابع استفاده می کنیم :
extern __m128i _mm_add_epi8(__m128i _A, __m128i _B);
extern __m128i _mm_add_epi16(__m128i _A, __m128i _B);
extern __m128i _mm_add_epi32(__m128i _A, __m128i _B);
extern __m64 _mm_add_si64(__m64 _A, __m64 _B);
extern __m128i _mm_add_epi64(__m128i _A, __m128i _B);
extern __m128i _mm_adds_epi8(__m128i _A, __m128i _B);
extern __m128i _mm_adds_epi16(__m128i _A, __m128i _B);
extern __m128i _mm_adds_epu8(__m128i _A, __m128i _B);
extern __m128i _mm_adds_epu16(__m128i _A, __m128i _B);
u مخفف unaligned هست
عددی هم که بعد از epi هست نشون میده عملیات روی داده چند بیتی انجام میشه مثلا epi8 یعنی جمع روی char که 8 بیت هست انجام میشه یا epi32 روی int که 32 بیته
مثال از استفاده :
std::vector<int> a={1,2,3,4};
std::vector<int> b={1,2,3,4};
__m128i* src = reinterpret_cast<__m128i*>(a.data());
__m128i* src2= reinterpret_cast<__m128i*>(b.data());
__m128i lhs=_mm_load_si128(src);
__m128i rhs=_mm_load_si128(src2);
//chon vector az no e int 32biti hast az epi32 estefade mikonim
__m128i result=_mm_add_epi32(lhs,rhs);//result inja shamele majmoo hast
برای ذخیره _mm128i داخل وکتور هم از یکی از این توابع :
//128 bit az _B dakhel _p zakhire mishe p bayad 16bit align shode bashe
extern void _mm_store_si128(__m128i *_P, __m128i _B);
//128 bit az _B dakhel _p zakhire mishe
extern void _mm_storeu_si128(__m128i *_P, __m128i _B);
//64 bit aval az Q dakhe p zakhire mishe
extern void _mm_storel_epi64(__m128i *_P, __m128i _Q);
پس با استفاده از توابع بالا میشه تابع جمع 2 وکتور رو به این شکل نوشت :
#include <iostream>
#include <emmintrin.h>
#include <vector>
std::vector<int> add(std::vector<int> a, std::vector<int> b)
{
std::vector<int> return_vec(a.size());
//marhale 1 tabdil be __m128i*
__m128i* src1 = reinterpret_cast<__m128i*>(a.data());
__m128i* src2 = reinterpret_cast<__m128i*>(b.data());
__m128i* dst = reinterpret_cast<__m128i*>(return_vec.data());
for (int i = 0; i < a.size(); i += 4){//chon 128bit yeja jam mishe 4ta 4ta mirim jolo
__m128i lhs = _mm_loadu_si128(src1 + i);//enteghal az vector be union
__m128i rhs = _mm_loadu_si128(src2 + i);
__m128i res = _mm_add_epi32(lhs, rhs);//jam zadan 2 union ba estefade az register haye XMM
_mm_storeu_si128(dst + i, res);//zakhire union dakhele vector result
//ya beshekl feshorde zir !
//_mm_storeu_si128(dst + i, _mm_add_epi32(_mm_loadu_si128(src1 + i), _mm_loadu_si128(src2 + i)));
}
return return_vec;
}
int main()
{
std::vector<int> a = { 1, 5, 6, 2 };
std::vector<int> b = { 4, 2, 3, 1 };
std::vector<int> res = add(a, b);
for (auto i : res){
std::cout << i << ' ';
}
return 0;
}
ویرایش :ضمنا این مثال آخری که من زدم صرفا نمونه بود و درست نیست. برای استفاده از وکتور باید allocator , deallocator مخصوص که دیتا 16bit alignتولید کنن هم بنویسید و بجای std::vector توی کد بالا از اون استفاده کنید . (چون alignment دروکتور ۱۶bit نیست )