Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extract bits with SIMD

I want to extract 8 bits from a register variable __mm256i src with 8 position specified by another __mm256i offset which is composed of 8 integers. For example: if offset is [1,3,5,21,100,200,201,202], I want to get 1st,3rd,5th,100th,200th,201st,202nd bits from src and pack them to a int8.

This question is similar to Extracting bits using bit manipulation, but I want a solution with SIMD instructions, since it is much faster.

like image 910
jianqiang Avatar asked Oct 19 '17 07:10

jianqiang


1 Answers

  1. Select high 3 bits in each element and select required 32-bit element with using of intrinsic _mm256_permutevar8x32_epi32().
  2. Select low 5 bits in each elements of vector and create bit mask with using of intrinsic _mm256_sllv_epi32().
  3. Pack result to int8 with using of _mm256_movemask_ps() (cast __m256i to __m256).

There is an example below:

uint8_t Select(__m256i offset, __m256i src)
{
    __m256i permutedSrc = _mm256_permutevar8x32_epi32(src, _mm256_srli_epi32(offset, 5));
    __m256i shift = _mm256_and_si256(offset, _mm256_set1_epi32(31));
    __m256i bitmask = _mm256_sllv_epi32(_mm256_set1_epi32(1), shift);
    __m256i mask = _mm256_cmpeq_epi32(_mm256_and_si256(permutedSrc, bitmask), _mm256_setzero_si256());
    return ~_mm256_movemask_ps(_mm256_castsi256_ps(mask));
}
like image 195
ErmIg Avatar answered Oct 24 '22 15:10

ErmIg