Как конвертировать два _pd в один _ps? - PullRequest
0 голосов
/ 04 февраля 2019

Я зацикливаю некоторые данные, вычисляю некоторые двойные и каждые 2 __m128d операции, я хочу сохранить данные в __m128 float.

Итак, 64 + 64 + 64 + 64 (2__m128d) хранится в 1 32 + 32 + 32 + 32 __m128.

Я делаю что-то вроде этого:

__m128d v_result;
__m128 v_result_float;

...

// some operations on v_result

// store the first two "slot" on float
v_result_float = _mm_cvtpd_ps(v_result);

// some operations on v_result
// I need to store the last two "slot" on float
v_result_float = _mm_cvtpd_ps(v_result); ?!?

Но это перезаписывает (очевидно) первые 2 числа с плавающей запятой "Слоты "каждый раз.

Как можно «пробелить» _mm_cvtpd_ps, чтобы начать вставку значений в «слот» 3 ° и 4 °, во второй раз?

Вот полный код:

__m128d v_pA;
__m128d v_pB;
__m128d v_result;
__m128 v_result_float;

float *pCEnd = pTest + roundintup8(blockSize);
for (; pTest < pCEnd; pA += 8, pB += 8, pTest += 8) {
    v_pA = _mm_load_pd(pA);
    v_pB = _mm_load_pd(pB);
    v_result = _mm_add_pd(v_pA, v_pB);
    v_result = _mm_max_pd(v_boundLower, v_result);
    v_result = _mm_min_pd(v_boundUpper, v_result);
    v_result = _mm_mul_pd(v_rangeLn2per12, v_result);
    v_result = _mm_add_pd(v_minLn2per12, v_result);

    // two double processed: store in 1° and 2° float slot
    v_result_float = _mm_cvtpd_ps(v_result);

    v_pA = _mm_load_pd(pA + 2);
    v_pB = _mm_load_pd(pB + 2);
    v_result = _mm_add_pd(v_pA, v_pB);
    v_result = _mm_max_pd(v_boundLower, v_result);
    v_result = _mm_min_pd(v_boundUpper, v_result);
    v_result = _mm_mul_pd(v_rangeLn2per12, v_result);
    v_result = _mm_add_pd(v_minLn2per12, v_result);

    // another two double processed: store in 3° and 4° float slot
    v_result_float = _mm_cvtpd_ps(v_result); // fail
    v_result_float = someFunction(v_result_float);
    _mm_store_ps(pTest, v_result_float);

    v_pA = _mm_load_pd(pA + 4);
    v_pB = _mm_load_pd(pB + 4);
    v_result = _mm_add_pd(v_pA, v_pB);
    v_result = _mm_max_pd(v_boundLower, v_result);
    v_result = _mm_min_pd(v_boundUpper, v_result);
    v_result = _mm_mul_pd(v_rangeLn2per12, v_result);
    v_result = _mm_add_pd(v_minLn2per12, v_result);

    // two double processed: store in 1° and 2° float slot
    v_result_float = _mm_cvtpd_ps(v_result);

    v_pA = _mm_load_pd(pA + 6);
    v_pB = _mm_load_pd(pB + 6);
    v_result = _mm_add_pd(v_pA, v_pB);
    v_result = _mm_max_pd(v_boundLower, v_result);
    v_result = _mm_min_pd(v_boundUpper, v_result);
    v_result = _mm_mul_pd(v_rangeLn2per12, v_result);
    v_result = _mm_add_pd(v_minLn2per12, v_result);

    // another two double processed: store in 3° and 4° float slot
    v_result_float = _mm_cvtpd_ps(v_result); // fail
    v_result_float = someFunction(v_result_float);      
    _mm_store_ps(pTest + 4, v_result_float);
}

1 Ответ

0 голосов
/ 04 февраля 2019

Вам нужно переместить младшие слова второго преобразования в старшие слова результата первого преобразования, используя movlhps (_mm_movelh_ps).Упрощенный пример:

#include <immintrin.h>

__m128d some_double_operation(__m128d);
__m128 some_float_operation(__m128);

void foo(double const* input, float* output, int size)
{
    // assuming everything is already nicely aligned ...
    for(int i=0; i<size; i+=4, input+=4, output+=4)
    {
        __m128d res_lo = some_double_operation(_mm_load_pd(input));
        __m128d res_hi = some_double_operation(_mm_load_pd(input+2));
        __m128 res_float = _mm_movelh_ps(_mm_cvtpd_ps(res_lo), _mm_cvtpd_ps(res_hi));
        __m128 res_final = some_float_operation(res_float);
        _mm_store_ps(output, res_final);
    }
}

Godbolt-Demo: https://godbolt.org/z/wgKjxN.

Если указано some_double_operation, компилятор, скорее всего, сохранит результат первой двойной операции в регистре, который не используетсявторой вызов функции, поэтому не требуется хранить что-либо в памяти.

...