I want to convert a vector of double precision values to char. I have to make two distinct approaches, one for SSE2 and the other for AVX2.
I started with AVX2.
__m128i sub_proc(__m256d& in)
{
__m256d _zero_pd = _mm256_setzero_pd();
__m256d ih_pd = _mm256_unpackhi_pd(in,_zero_pd);
__m256d il_pd = _mm256_unpacklo_pd(in,_zero_pd);
__m128i ih_si = _mm256_cvtpd_epi32(ih_pd);
__m128i il_si = _mm256_cvtpd_epi32(il_pd);
ih_si = _mm_shuffle_epi32(ih_si,_MM_SHUFFLE(3,1,2,0));
il_si = _mm_shuffle_epi32(il_si,_MM_SHUFFLE(3,1,2,0));
ih_si = _mm_packs_epi32(_mm_unpacklo_epi32(il_si,ih_si),_mm_unpackhi_epi32(il_si,ih_si));
return ih_si;
}
__m128i proc(__m256d& in1,__m256d& in2)
{
__m256d _zero_pd = _mm_setzeros_pd();
__m128i in1_si = sub_proc(in1);
__m128i in2_si = sub_proc(in2);
return _mm_packs_epi16(in1_si,in2_si);
}
int main()
{
double input[32] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32};
char output[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
char check[8];
double* ibeg = input;
char* obeg = output;
for(int i=0;i<32;i+=8)
{
__m256d in1 = _mm256_loadu_pd(ibeg);
__m256d in2 = _mm256_loadu_pd(ibeg+4);
__m128i tmp = proc(in1,in2);
_mm_storeu_si128(reinterpret_cast<__m128i*>(check),tmp);
std::copy(check,check+8,std::ostream_iterator<int>(std::cout," "));
std::cout<<std::endl;
_mm_storeu_si128(reinterpret_cast<__m128i*>(obeg+i),tmp);
}
}
At the end of this algorithm the output contains:
1,2,3,4,0,0,0,0,9,10,11,12,0,0,0,0,17,18,19,20,0,0,0,0,25,26,27,28,0,0,0,0
My first investigation shows me that if in the function proc
I change:
return _mm_packs_epi16(in1_si,in2_si);
to:
return _mm_packs_epi16(in2_si,in1_si);
Then the output contains:
5,6,7,8,0,0,0,0,13,14,15,16,0,0,0,0,21,22,23,24,0,0,0,0,29,30,31,31,0,0,0,0
I have not worked out how to shuffle the low and high part of in2_si
.
Is there a better (faster, more efficient) way to transform double precision numbers to char using SIMD ?
If you want to convert e.g. 16
double
s to 16char
s per iteration using AVX/SSE then here is some code that works:Compile and run:
Note that the above code only requires AVX (no need for AVX2).