c++ - 如何将两个_pd 转换为一个_ps?

标签 c++ type-conversion simd sse2

我正在循环一些数据,计算一些 double 和每 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 个 float “插槽”。

我如何“间隔”_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);
}

最佳答案

您需要使用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-演示:https://godbolt.org/z/wgKjxN .

如果 some_double_operation 是内联的,编译器可能会将第一个 double 运算的结果保存在一个寄存器中,而该寄存器不会被第二次函数调用使用,因此不需要将任何内容存储到内存中。

关于c++ - 如何将两个_pd 转换为一个_ps?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54517648/

相关文章:

c++ - 游戏/程序如何计算高于 C++ 限制的数字?

C++:堆栈上的未初始化(?)数组(关于 OpenGL 的示例)

c++ - LLVM 中的 SIMD vector 内存加载

c++ - 在哪里初始化 SSE 常量

c++ - 在4个__m256d寄存器中找到4个最小值

c++ - 自增自减运算符重载

c++ - 一个进程可以从它的虚拟内存中的任何地址读/写吗?

mysql - SQL/SAP HANA SQL 数据类型

c - 我还是 C 的新手,我不知道为什么我的 float 结果是随机的(也许是类型提升规则?)

c# - 将 Int 转换为两个 Shorts 返回填充数据/负值