繁体   English   中英

SSE _mm_dp_ps 大小结果

[英]SSE _mm_dp_ps size result

我开始使用 SSE 进行操作。 我想用_mm_dp_ps制作两个点积,并将第一个结果保存在aux_sse ,将第二个结果保存在aux_sse B 是值为 1 的 8 元素向量。

由于每对只需要两个浮点数,因此我做了以下代码:

    printf("A  \n");
    for(i = 0; i < M; i++){
        for(j = 0; j < ele; j++){
            A[i*ele+j] = i*ele+j;
            printf(" %f ", A[i*ele+j]);
        }
        printf("\n");
    }
    
    float aux[ele*M];
    float aux2[ele*M];
    __m128 *A_sse = (__m128*) A;
    __m128 *B_sse = (__m128*) B;
    __m128 *aux_sse  = (__m128*) aux;
    __m128 *aux2_sse  = (__m128*) aux2;
    for(int i = 0; i < M; i++)
    {
        *aux_sse =  _mm_dp_ps (*A_sse, *B_sse,  0xFF);
        printf("%f \n", aux[i]);

        B_sse ++;
        A_sse++;
        *aux2_sse = _mm_dp_ps (*A_sse, *B_sse,  0xFF);
        printf("%f \n", aux2[i]);

        B_sse --;
        A_sse ++;

        aux_sse+= sizeof(char);
        aux2_sse+= sizeof(char);
    }

我得到以下错误输出:

A  
 0.000000  1.000000  2.000000  3.000000  4.000000  5.000000  6.000000  7.000000 
 8.000000  9.000000  10.000000  11.000000  12.000000  13.000000  14.000000  15.000000 
6.000000 
22.000000 
6.000000 
22.000000 

根据这个

使用 imm8 中的高 4 位将 a 和 b 中的压缩单精度(32 位)浮点元素有条件地相乘,对四个乘积求和,并使用 imm8 的低 4 位有条件地将和存储在 dst 中。

我知道在 imm8 中我们在元素中指定要保存结果的元素。

据我了解,即使结果在输出向量的 4 个元素中,如果我只使用aux_sse+= sizeof(char)增加一个元素,结果应该被覆盖,并且会出现所需的结果。 但是,我看到情况并非如此。

如果我在打印 aux 和 aux2 的结果时进行以下修改,则输出是正确的。

printf("%f \n", aux[i*4]);
printf("%f \n", aux2[i*4]);

输出:

6.000000 
22.000000 
38.000000 
54.000000 

我正在使用 gcc 编译器。 有谁知道问题是什么? 任何答案都会有所帮助。

编辑:

我需要 aux 和 aux2 的元素来对应每次迭代:

aux[i] = dot_product 在迭代 i 中执行

aux_sse+= sizeof(char); 是一种写aux_sse+=1的荒谬方式,即前进 16 个字节,也就是 4 个浮点数,即sizeof(__m128) == sizeof(*aux_sse) == 16

因此,如果您还通过浮点索引访问数组,是的,如果您只为每个包含 4 个浮点数的向量将i增加 1,则必须将其缩放 4。

通常使用_mm_store_ps(&aux[i], v);更容易_mm_store_ps(&aux[i], v); 而不是跟踪__m128*变量来访问相同的数组。 并且做i+=4所以i实际上是在索引你拥有的 4 元素组的开始,而不是需要缩放它。 这使得编写像i < M-3这样的循环边界变得更容易。

另请注意,您应该使用alignas(16) float aux[ele*M]; 如果您想对数组进行需要对齐的访问。 GCC 会注意到您在做什么,并会在它可以看到数组的使用方式时为您对齐数组,但通常不要指望它。


或者您是否只想存储单个float结果,而不是为每组 4 个输入存储4 个相同的点积? 在这种情况下,您应该提取低标量元素,例如_mm_store_ss (&aux[i], v) _mm_cvtss_f32(v)将向量的低元素作为标量float

如果需要,您可以手动执行四个 4 元素点积,生成 1 个包含 4 个结果的向量。 _mm_mul_ps然后可能是 2x _mm_hadd_ps (SSE3) 水平减少,一种转置和添加。 (由@mainactual 推荐)

dpps在 Skylake 和类似的 Intel CPU ( https://uops.info ) 上是 4 dpps ,所以如果你有多个点积要做,那就不好了。

为了避免 SSE3,您可以使用_mm_shuffle_ps ( shufps ) 从 2 个向量中选取元素,或者一些_mm_unpacklo_ps / unpackhi 可能有用,或者pd版本可以将元素对保持在一起。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM