如何访问 256 位 ps 向量的组件
Posted
技术标签:
【中文标题】如何访问 256 位 ps 向量的组件【英文标题】:How to access components of the 256 bit ps vector 【发布时间】:2012-10-21 17:31:41 【问题描述】:如何高效访问256位向量的元素?例如,我用
计算了点积c = _mm256_dp_ps(a, b, 0xff);
那么如何访问c中的值呢?我需要同时获得高位和低位,我是否正确理解我首先需要像这样提取128位部分:
r0 = _mm256_extractf128_ps(c,0);
r1 = _mm256_extractf128_ps(c,1);
然后才提取浮点数:
_MM_EXTRACT_FLOAT(fr0, r0, 0);
_MM_EXTRACT_FLOAT(fr1, r1, 0);
return fr0 + fr1;
【问题讨论】:
如果您只是为单个点积进行如此多的打包/解包,那么您可能需要考虑重新设计相关代码以将此类数据移动降至最低。 欢迎提出建议。我需要为 16 个浮点数的向量计算点积。 AVX 路由对我来说似乎是最佳选择,但我确实对代码不满意。 每个向量在内存中是否连续? 这很棘手,因为点积指令有点奇怪。另一种方法是将它们向量相乘,然后做一个二叉减少树的加法。 好的,看来 _mm256_extractf128_ps 可以使用,编译器只是将其优化为 VZEROUPPER 并返回 xmm0,但我决定放弃 AVX 并使用 SSE4。对于中等大小的向量,这似乎更方便,并且比 256 位上的 mm256_dp_ps 更快。 mm256_dp_ps 真的很慢。 【参考方案1】:好吧,您可以只存储到内存中,然后使用标量:
float v[8];
*(__m256)(v) = _mm256_dp_ps(a, b, 0xff);
float result = v[0] + v[4];
您还可以将 256 位寄存器的上半部分交换到下半部分并添加,如下所示:
__m256 c = _mm256_dp_ps(a, b, 0xff);
__m256 d = _mm256_permute2f128_ps(c, c, 1);
__m256 result = _mm256_add_ps(c, d);
一次做 4x 8 宽的点积并将它们一起减少可能比任何一种选择都快得多。草图:
d0 = _mm256_dp_ps(a[0], b[0], 0xff);
d1 = _mm256_dp_ps(a[1], b[1], 0xff);
d2 = _mm256_dp_ps(a[2], b[2], 0xff);
d3 = _mm256_dp_ps(a[3], b[3], 0xff);
d01 = _mm256_permute_ps(d0, d1, ...);
d23 = _mm256_permute_ps(d2, d3, ...);
d0123 = _mm256_permute_ps(d01, d23, ...);
d0123upper = _mm256_permute2f128_ps(d0123, d0123, 1);
d = _mm256_add_ps(d0123upper, d0123); // lower 128 bits contain the results of 4 8-wide dot products
【讨论】:
不理解更快的选项,如何置换这些:d01 = _mm256_permute_ps(d0, d1, ...);该方法只接收一个寄存器 @Shahar 如果 d0 包含浮点数 d0.0、d0.1 到 d0.8,并且 d1 包含 d1.0、d1.1 到 d1.8 等,则 d0123 应该包含 d0.0, d1.0、d2.0、d3.0、d0.4、d1.4、d2.4、d3.4。我知道我提到的内在函数并没有完全做到这一点,但它需要某种排列......欢迎提出建议;)【参考方案2】:没有有效的方法来做到这一点。 dp_ps 操作本身很慢,后续提取也很慢。除非可以批量处理更多数据,否则使用 SSE4 指令计算点积并使用 128 位比使用 256 位更快。
【讨论】:
您只问如何做到这一点,而不是如何快速做到这一点:) 我也发布了一些代码示例来做批处理点产品,这会更快,可能比 SSE4 更快。此外,还有两种不同的方式来获得单点积的结果。以上是关于如何访问 256 位 ps 向量的组件的主要内容,如果未能解决你的问题,请参考以下文章