SSE作用于元素个数不是4的倍数的数组

SSE works on the array that the number of the elements is not the multiple of four

大家。

我的问题是如果我有如下三个数组

float a[7] = {1.0, 2.0, 3.0, 4.0, 
              5.0, 6.0, 7.0};
float b[7] = {2.0, 2.0, 2.0, 2.0,
              2.0, 2.0, 2.0};
float c[7] = {0.0, 0.0, 0.0, 0.0,
              0.0, 0.0, 0.0};

我想按如下方式执行逐元素乘法运算

c[i] = a[i] * b[i], i = 0, 1, ..., 6

对于前四个元素,我可以使用 SSE 内在函数如下

__m128* sse_a = (__m128*) &a[0];
__m128* sse_b = (__m128*) &b[0];
__m128* sse_c = (__m128*) &c[0];

*sse_c = _mm_mul_ps(*sse_a, *sse_b);

c中的内容将是

c[0] = 2.0, c[1] = 4.0, c[2] = 6.0, c[3] = 8.0
c[4] = 0.0, c[5] = 0.0, c[6] = 0.0

索引4、5、6剩下的三个数,我用下面的代码 执行逐元素乘法运算

sse_a = (__m128*) &a[4];
sse_b = (__m128*) &b[4];
sse_c = (__m128*) &c[4];

float mask[4] = {1.0, 1.0, 1.0, 0.0};
__m128* sse_mask = (__m128*) &mask[0];

*sse_c = _mm_add_ps( *sse_c, 
    _mm_mul_ps( _mm_mul_ps(*sse_a, *sse_b), *sse_mask ) );

c[4-6]中的内容将是

c[4] = 10.0, c[5] = 12.0, c[6] = 14.0, which is the expected result.

_mm_add_ps() 并行相加四个浮点数,第一个、第二个、第三个浮点数分配在数组a、b、c的索引4、5、6分别。 但是第四个浮点数没有分配给数组。 为了避免无效的内存访问,我乘以 sse_mask 使第四个数字为零,然后将结果添加回 sse_c(数组 c)。

但是我想知道它是否安全?

非常感谢。

您的数学运算似乎是正确的,但我真的不确定像您这样使用强制转换是否是在 __m128 变量中加载和存储数据的方法。

加载和存储

要将数据从数组加载到 __m128 变量,您应该使用 __m128 _mm_load_ps (float const* mem_addr)__m128 _mm_loadu_ps (float const* mem_addr) 。很容易弄清楚这里是什么,但需要一些精确度:

  • 对于涉及内存访问或操作的操作,通常有两个函数做同样的事情,例如 loadloadu 。第一个要求你的内存在 16 字节边界上对齐,而 u 版本没有这个要求。如果您不知道内存对齐,请使用 u 版本。
  • 您还有 load_psload_pd。区别:s 代表单精度(好旧的 float),d 代表双精度,即双精度。当然,每个 __m128 变量只能放两个双精度数,但是 4 个浮点数。

因此从数组加载数据非常简单,只需执行:__m128* sse_a = _mm_loadu_ps(&a[0]);。对 b 做同样的事情,但对 c 来说,这真的取决于。如果你只想把乘法的结果放在里面,把它初始化为0是没有用的,加载它,然后把乘法的结果加进去,最后再取回来。

您应该使用 load 的挂起操作来存储 void _mm_storeu_ps (float* mem_addr, __m128 a) 的数据。因此,一旦乘法完成并且结果为 sse_c,只需执行 _mm_storeu_ps(&c[0@, sse_c) ;

算法

使用掩码背后的想法很好,但您有更简单的方法:从 a[3] 加载和存储数据(b 和 c 相同)。这样一来,它就会有 4 个元素,那么就不需要使用任何遮罩了?是的,已经对第三个元素进行了一项操作,但这将是完全透明的:store 操作只会用新值替换旧值。因为两者是平等的,所以这不是问题。

一种替代方法是在你的数组中存储 8 个元素,即使你只需要 7 个元素。这样你就不必担心内存是否被分配,不需要像上面那样的特殊逻辑来支付 3 个的成本浮动,这在所有最近的计算机上都没有。