[英]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.