SSE _mm_dp_ps大小结果

问题描述

我开始使用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,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 

根据this

使用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] =在第i次迭代中执行的dot_product

解决方法

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

因此,如果您还通过float索引访问数组,是的,如果对每个4个float的向量仅将i递增1,则必须将其缩放4。

通常,使用_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 oups,因此如果要处理多个点积,那就不好了。

为避免SSE3,您可以使用_mm_shuffle_psshufps)从2个向量中选择元素,或者使用某些_mm_unpacklo_ps / unpackhi可能有用,或者使用{{1 }}版本,将成对的元素保持在一起。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...