Внутренние свойства SSE приводят к тому, что обычная операция с плавающей запятой возвращает -1. # INV - PullRequest
7 голосов
/ 29 января 2012

У меня проблема с методом SSE, который я пишу, который выполняет обработку звука.Я реализовал случайную функцию SSE, основанную на статье Intel:

http://software.intel.com/en-us/articles/fast-random-number-generator-on-the-intel-pentiumr-4-processor/

У меня также есть метод, который выполняет преобразования из Float в S16 с использованием SSE, преобразование выполняется довольнопросто следующим образом:

unsigned int Float_S16LE(float *data, const unsigned int samples, uint8_t *dest)
{
  int16_t *dst = (int16_t*)dest;
  const __m128 mul = _mm_set_ps1((float)INT16_MAX);
   __m128 rand;
  const uint32_t even = count & ~0x3;
  for(uint32_t i = 0; i < even; i += 4, data += 4, dst += 4)
  {
    /* random round to dither */
    FloatRand4(-0.5f, 0.5f, NULL, &rand);

    __m128 rmul = _mm_add_ps(mul, rand);
    __m128 in = _mm_mul_ps(_mm_load_ps(data),rmul);
    __m64 con = _mm_cvtps_pi16(in);

    memcpy(dst, &con, sizeof(int16_t) * 4);
  }
}

FloatRand4 определяется следующим образом:

static inline void FloatRand4(const float min, const float max, float result[4], __m128 *sseresult = NULL)
{
  const float delta  = (max - min) / 2.0f;
  const float factor = delta / (float)INT32_MAX;
  ...
}

Если sseresult != NULL, возвращается результат __m128 и result не используется.Это прекрасно работает в первом цикле, но в следующем цикле delta становится -1.#INF вместо 1.0.Если я закомментирую строку __m64 con = _mm_cvtps_pi16(in);, проблема исчезнет.

Я думаю, что FPU переходит в неизвестное состояние или что-то в этом роде.

Ответы [ 2 ]

9 голосов
/ 29 января 2012

Смешивание SSE Целочисленная арифметика и (обычная) математика с плавающей точкой.Может привести к странным результатам, потому что оба работают в одних и тех же регистрах.Если вы используете:

_mm_empty()

, FPU сбрасывается в правильное состояние.Microsoft имеет Руководство по использованию EMMS

1 голос
/ 29 января 2012
  • _mm_load_ps не гарантирует выравнивание нагрузки. данные с плавающей точкой * могут быть выровнены до 4 байтов вместо 16 _ => _mm_loadu_ps
  • memcpy, вероятно, убьет преимущества, достигнутые с SSE, вы должны использовать команду store для __m64, но здесь снова позаботьтесь о выравнивании. Если невозможно выполнить невыровненный поток или сохранить __m64, я бы либо оставил его внутри _m128i и сделал запись в маске с помощью _mm_maskmoveu_si128, либо сохранил эти 8 байт вручную.

http://msdn.microsoft.com/en-us/library/bytwczae.aspx

...