c - 使用 SSE 内在函数将 4 个点积存储到 C 中的连续数组中的最有效方法

标签 c sse simd intrinsics dot-product

我正在使用 SSE 内在函数为 Intel x86 Nehalem 微架构优化一些代码。

我的程序的一部分计算 4 个点积,并将每个结果添加到数组的连续 block 中的先前值。更具体地说,

tmp0 = _mm_dp_ps(A_0m, B_0m, 0xF1);
tmp1 = _mm_dp_ps(A_1m, B_0m, 0xF2);
tmp2 = _mm_dp_ps(A_2m, B_0m, 0xF4);
tmp3 = _mm_dp_ps(A_3m, B_0m, 0xF8);

tmp0 = _mm_add_ps(tmp0, tmp1);
tmp0 = _mm_add_ps(tmp0, tmp2);
tmp0 = _mm_add_ps(tmp0, tmp3);
tmp0 = _mm_add_ps(tmp0, C_0n);

_mm_storeu_ps(C_2, tmp0);

请注意,我将使用 4 个临时 xmm 寄存器来保存每个点积的结果。在每个 xmm 寄存器中,结果被放入相对于其他临时 xmm 寄存器的唯一 32 位,因此最终结果如下所示:

tmp0= R0-零-零-零

tmp1= 零-R1-零-零

tmp2= 零-零-R2-零

tmp3= 零-零-零-R3

我将每个 tmp 变量中包含的值合并到一个 xmm 变量中,方法是按照以下说明对它们求和:

tmp0 = _mm_add_ps(tmp0, tmp1);
tmp0 = _mm_add_ps(tmp0, tmp2);
tmp0 = _mm_add_ps(tmp0, tmp3);

最后,我将包含所有 4 个点积结果的寄存器添加到数组的连续部分,以便数组的索引按点积递增,就像这样(C_0n 是数组中当前的 4 个值待更新;C_2是指向这4个值的地址):

tmp0 = _mm_add_ps(tmp0, C_0n);
_mm_storeu_ps(C_2, tmp0);

我想知道是否有更简单、更有效的方法来获取点积的结果并将它们添加到数组的连续 block 中。这样,我在只有 1 个非零值的寄存器之间进行了 3 次加法运算。似乎应该有更有效的方法来解决这个问题。

感谢所有帮助。谢谢。

最佳答案

对于这样的代码,我喜欢存储 A 和 B 的“转置”,以便将 {A_0m.x, A_1m.x, A_2m.x, A_3m.x} 存储在一个 vector 中,等等。然后您可以仅使用乘法和加法来计算点积,完成后,您可以在一个 vector 中获得所有 4 个点积,而无需任何改组。

这在光线追踪中经常使用,一次针对一个平面测试 4 条光线(例如,在遍历 kd 树时)。但是,如果您无法控制输入数据,那么进行转置的开销可能不值得。该代码也将在 SSE4 之前的机器上运行,尽管这可能不是问题。


关于现有代码的一个小效率说明:而不是这个

tmp0 = _mm_add_ps(tmp0, tmp1);
tmp0 = _mm_add_ps(tmp0, tmp2);
tmp0 = _mm_add_ps(tmp0, tmp3);
tmp0 = _mm_add_ps(tmp0, C_0n);

这样做可能稍微好一点:

tmp0 = _mm_add_ps(tmp0, tmp1);  // 0 + 1 -> 0
tmp2 = _mm_add_ps(tmp2, tmp3);  // 2 + 3 -> 2
tmp0 = _mm_add_ps(tmp0, tmp2);  // 0 + 2 -> 0
tmp0 = _mm_add_ps(tmp0, C_0n);

因为前两个 mm_add_ps 现在是完全独立的了。另外,我不知道添加与改组的相对时间,但这可能会稍微快一些。


希望对您有所帮助。

关于c - 使用 SSE 内在函数将 4 个点积存储到 C 中的连续数组中的最有效方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4171241/

相关文章:

c++ - 你能调试自动矢量化循环吗?

x86 微架构/SIMD 市场份额

c - Strtol函数的实现——cast

c - 动态分配的函数中的局部指针变量会发生什么?

c - 在声明时初始化 union 数组

c - SIMD SSE2 __m128i包含4个int32_t如何快速找到每个大于或小于0的整数

c++ - SSE 性能 Eigen

c++ - char 和 wchar_t 的模板没有给出匹配的成员

c - 是否可以使用 autoconf 检查 nvcc 编译?

rust - SIMD 代码在 Debug 中有效,但在 Release 中无效