问题描述
我开始使用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_ps
(shufps)从2个向量中选择元素,或者使用某些_mm_unpacklo_ps
/ unpackhi可能有用,或者使用{{1 }}版本,将成对的元素保持在一起。