在 C 中使用英特尔内在函数加载和存储复杂的浮点数

Posted

技术标签:

【中文标题】在 C 中使用英特尔内在函数加载和存储复杂的浮点数【英文标题】:Load and store complex floats with Intel intrinsics in C 【发布时间】:2016-10-25 10:32:36 【问题描述】:

我正在尝试使用__m128 向量单位对复数浮点数进行一些计算。使用__m128,我可以存储两个complex floats,因为每个复数由两个浮点数组成,一个实部和一个虚部。

到目前为止,一切都很好。

当我必须将我的答案“收集”到 one complex float 时,我的问题就出现了。假设我有两个 __m128 向量,以及存储在这两个向量中的四个复数。例如,我可以使用 _mm_add_ps 内在函数将两个向量(两个和两个浮点数)相加,但是如何将结果向量中的两个复数“减少”为一个复数(两个 floats)和将其存储在数组中?

同样,如果我想从我的数组中获取一个复数并将其存储在一个向量中两次(实部在第 1 块和第 3 块中,虚部在第 2 块和第 4 块中),我该怎么做完成这个?

【问题讨论】:

【参考方案1】:

如果您想在复数上使用 SIMD,请首先不要以交错/压缩格式存储复数。将实部和虚部存储在单独的数组中,这样您就可以并行执行四次复数乘法运算,而无需任何改组(或像 HSUBPS 这样的慢速水平运算)。

直接回答这个问题:做the first stage of a horizontal sum:将高64降低到另一个向量的低64(使用_mm_movehl_ps),然后_mm_add_ps,就像我对该问题的回答所示。

然后您可以MOVLPS 存储低 2 个浮点数:void _mm_storel_pi (__m64 *p, __m128 a)。看起来你需要烦人的转换才能使用它:/ MOVSD 也可以工作,但需要多一个字节来编码。


同样,如果我想从我的数组中获取一个复数并将其存储在一个向量中两次

使用MOVDDUP 从内存或其他寄存器广播 64 位。您需要进行一些强制转换才能使用内在函数,但这很好(它们不会编译为任何指令,并且在 float 数据上使用诸如 MOVDDUP 之类的 double 指令不会对任何现有 CPU 造成任何损失):

__m128d _mm_loaddup_pd(double const * dp);
__m128d _mm_movedup_pd(__m128d a);

与 PMOVZX (this design flaw is one of my major pet peeves with intrinsics) 不同,至少它具有负载固有特性。

【讨论】:

以上是关于在 C 中使用英特尔内在函数加载和存储复杂的浮点数的主要内容,如果未能解决你的问题,请参考以下文章

在 C 中存储和使用具有 1,000,000 位有效数字的浮点数的最有效方法是啥?

如何将一个巨大的头部分配数组设置为特定的浮点数 C++

你如何使用霓虹内在函数加载 3 个浮点数

香草 C 替代英特尔内在函数? [关闭]

使用内在函数将双 SSE2/AVX/AVX512 存储为浮点数的最佳方法

[ C语言 ]一篇带你了解浮点型在内存中的存储