SSE извлекает целые числа из __m128 для индексации массива - PullRequest
3 голосов
/ 10 ноября 2011

В каком-то коде, который я преобразовал в SSE, я предварительно формирую трассировку лучей, отслеживая 4 луча за раз, используя типы данных __m128.

В методе, где я определяю, какие объекты попадают первыми, я перебираю все объекты, проверяю их на пересечение и создаю маску, представляющую, какие лучи имели пересечение раньше, чем было найдено ранее.

Мне также нужно сохранить данные об идентификаторах объектов, которые соответствуют лучшим временам попадания. Я делаю это, поддерживая тип данных __m128 с именем objectNo, и использую маску, определенную по времени пересечения, для обновления objectNo следующим образом:

objectNo = _mm_blendv_ps(objectNo,_mm_set1_ps((float)pobj->getID()),mask);

Где pobj-> getID () вернет целое число, представляющее идентификатор текущего объекта. Создание этого приведения и использование наложения, казалось, было наиболее эффективным способом обновления objectNo для всех 4 лучей.

После того, как все пересечения проверены, я пытаюсь извлечь objectNo's индивидуально и использовать их для доступа к массиву, чтобы зарегистрировать пересечение. Чаще всего я пробовал это:

int o0 = _mm_extract_ps(objectNo, 0);
prv_noHits[o0]++;

Однако это приводит к аварийному завершению с EXC_BAD_ACCESS, поскольку извлечение числа с плавающей запятой со значением 1.0 преобразуется в int со значением 1065353216.

Как правильно распаковать __m128 в слоты, которые можно использовать для индексации массива?

1 Ответ

4 голосов
/ 10 ноября 2011

Есть две встроенные функции преобразования SSE2, которые, кажется, делают то, что вы хотите:

  • _mm_cvtps_epi32()
  • _mm_cvttps_epi32()

http://software.intel.com/sites/products/documentation/studio/composer/en-us/2011/compiler_c/intref_cls/common/intref_sse2_int_conversion.htm

Они преобразуют 4 FP с одинарной точностью в 4 32-битных целых числа.Первый делает это с округлением.Второй использует усечение.

Таким образом, их можно использовать так:

int o0 = _mm_extract_epi32(_mm_cvtps_epi32(objectNo), 0);
prv_noHits[o0]++;

РЕДАКТИРОВАТЬ: В зависимости от того, что вы пытаетесь сделать, я чувствую этоможно оптимизировать следующим образом:

__m128i ids = _mm_set1_epi32(pobj->getID());

//  The mask will need to change
objectNo = _mm_blend_epi16(objectNo,ids,mask);

int o0 = _mm_extract_epi32(objectNo, 0);
prv_noHits[o0]++;

Эта версия избавляет от ненужных преобразований.Но вам нужно будет использовать другой вектор маски.

РЕДАКТИРОВАТЬ 2: Вот способ, которым вам не придется менять свою маску:

__m128 ids = _mm_castsi128_ps(_mm_set1_epi32(pobj->getID()));

objectNo = _mm_blendv_ps(objectNo,ids,mask);

int o0 = _mm_extract_ps(objectNo, 0);
prv_noHits[o0]++;

Обратите внимание, что встроенный _mm_castsi128_ps() не отображает никаких инструкций.Это просто побитовое преобразование типов данных из __m128i в __m128, чтобы обойти "типичность" в C / C ++.

...