У меня есть следующий код, который компилируется с помощью GCC с использованием флага -msse4
, но проблема в том, что счетчик всплывающих окон получает только последние четыре 8 бита преобразованного типа __m128i
. По сути, я хочу подсчитать все 16 чисел внутри типа __m128i
, но я не уверен, какой встроенный вызов функции сделать после создания переменной popA
. Каким-то образом popA
должно быть преобразовано в целое число, содержащее все 128 бит информации? Я полагаю, что их _mm_cvtsi128_si64
и используется несколько операций в случайном порядке, но моя ОС 32-разрядная. Есть только метод перемешивания и использование _mm_cvtsi128_si32
?
РЕДАКТИРОВАТЬ: Если метод перемешивания является единственным вариантом, мне нужна помощь в его реализации для моей 32-разрядной ОС, пожалуйста.
Вот код.
#include <stdio.h>
#include <smmintrin.h>
#include <emmintrin.h>
int main(void)
{
int A = 1;
__m128i popA = _mm_set_epi8( A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A);
unsigned int integer = _mm_cvtsi128_si32(popA);
//long long LONG = _mm_cvtsi128_si64(popA);//my OS is 32-bits so no luck here
printf("integer = %d\n", integer);
int pop = _mm_popcnt_u32(integer);
//int popLONG = _mm_popcnt_u64(LONG);
printf("popcount = %d\n", pop);
//printf("popcount LONG = %d\n", popLONG);
return 0;
}
РЕДАКТИРОВАТЬ 2: этот, наконец, запускается (с флагами компилятора GCC -msse -msse2 -msse3 -msse4
), хотя я не уверен, что вывод для pop_count1()
правильный.
Выход: pop_count1(): 1799 1799 1799 1799 1799 1799 1799 1799
pop_count2():population count for each byte: 1 1 1 1 1 1 1 1 0 1 2 3 4 5 6 7
#include <stdio.h>
#include <xmmintrin.h>
#include <emmintrin.h>
#include <mmintrin.h>
#include <stdint.h>
#include <tmmintrin.h>
void print128_num(__m128i var)
{
uint16_t *val = (uint16_t*) &var;
printf("pop_count1(): %i %i %i %i %i %i %i %i \n",
val[0], val[1], val[2], val[3], val[4], val[5],
val[6], val[7]);
}
static __m128i parallelPopcnt16bytes (__m128i xmm)//for pop_count2
{
const __m128i mask4 = _mm_set1_epi8 (0x0F);
const __m128i lookup = _mm_setr_epi8 (0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4);
__m128i low, high, count;
low = _mm_and_si128 (mask4, xmm);
high = _mm_and_si128 (mask4, _mm_srli_epi16 (xmm, 4));
count = _mm_add_epi8 (_mm_shuffle_epi8 (lookup, low), _mm_shuffle_epi8 (lookup, high));
return count;
}
void pop_count1()
{
int A = 1;
__m128i in = _mm_set_epi8( A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A);
__m128i bit0 = _mm_set1_epi8( 0x80 );
__m128i mask0 = _mm_and_si128( in, bit0 );
__m128i sum = _mm_cmpeq_epi8( mask0, _mm_setzero_si128() );
/* general pattern */
__m128i bit1 = _mm_set1_epi8( 0x40 );
__m128i mask1 = _mm_and_si128( in, bit1 );
mask1 = _mm_cmpeq_epi8( mask1, _mm_setzero_si128() );
sum = _mm_add_epi8( sum, mask1 );
/* next bit */
__m128i bit2 = _mm_set1_epi8( 0x20 );
__m128i mask2 = _mm_and_si128( in, bit2 );
mask2 = _mm_cmpeq_epi8( mask2, _mm_setzero_si128() );
sum = _mm_add_epi8( sum, mask2 );
__m128i bit3 = _mm_set1_epi8( 0x10 );
__m128i mask3 = _mm_and_si128( in, bit3 );
mask3 = _mm_cmpeq_epi8( mask3, _mm_setzero_si128() );
sum = _mm_add_epi8( sum, mask3 );
__m128i bit4 = _mm_set1_epi8( 0x08 );
__m128i mask4 = _mm_and_si128( in, bit4 );
mask4 = _mm_cmpeq_epi8( mask4, _mm_setzero_si128() );
sum = _mm_add_epi8( sum, mask4 );
__m128i bit5 = _mm_set1_epi8( 0x04 );
__m128i mask5 = _mm_and_si128( in, bit5 );
mask5 = _mm_cmpeq_epi8( mask5, _mm_setzero_si128() );
sum = _mm_add_epi8( sum, mask5 );
__m128i bit6 = _mm_set1_epi8( 0x02 );
__m128i mask6 = _mm_and_si128( in, bit6 );
mask6 = _mm_cmpeq_epi8( mask6, _mm_setzero_si128() );
sum = _mm_add_epi8( sum, mask6 );
__m128i bit7 = _mm_set1_epi8( 0x01 );
__m128i mask7 = _mm_and_si128( in, bit7 );
mask7 = _mm_cmpeq_epi8( mask7, _mm_setzero_si128() );
sum = _mm_add_epi8( sum, mask7 );
/* finish up */
sum = _mm_sub_epi8( _mm_setzero_si128(), sum );
print128_num(sum);
}
void pop_count2()
{
int index;
__m128i testVector = _mm_set_epi8 (1, 2, 4, 8, 16, 32, 64, 128, 0, 1, 3, 7, 15, 31, 63, 127);
__m128i counts = parallelPopcnt16bytes (testVector);
printf ("pop_count2():population count for each byte:");
for (index = 15; index >= 0; index--)
{
uint8_t *bytes = (void *) &counts;
printf (" %d", bytes [index]);
}
printf ("\n");
}
int main(void)
{
pop_count1();
pop_count2();
return 0;
}
int
, а также бесполезно в 32-разрядной ОС использовать 64-разрядные данные. popcnt — это не швейцарский армейский нож инструкций, который пока находится в зачаточном состоянии. Возможно, к SSE 5 это будет что-то отличное. - person pandoragami   schedule 08.07.2013_mm_and()
, а не_mm_andps
. И последовательность 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01. На самом деле не имеет значения, в каком порядке вы их делаете, если вы используете каждое значение разряда ровно один раз. - person Potatoswatter   schedule 08.07.2013__m128i mask0 = _mm_and( in, bit0 );
popcount.c|10|error: incompatible types when initializing type '__m128i' using type 'int'
. Я добавил флаги-msse -msse2 -msse3 -msse4
и использую заголовки#include <stdio.h> #include <smmintrin.h> #include <emmintrin.h> #include <mmintrin.h>
Что еще может быть? - person pandoragami   schedule 08.07.2013_mm_and
, и у них нет ни одного для__m128i
, поэтому я думаю, что нет способа замаскироватьint
этого типа. - person pandoragami   schedule 08.07.2013_mm_and_si128
- person Paul R   schedule 08.07.2013popcnt
может одновременно видеть только самые правые 32 бита, поэтому 96-битные игнорируются во время каждой операции. Не очень эффективно, если вы спросите меня. - person pandoragami   schedule 08.07.2013