如何存储__m128d SIMD向量作为双打的内容,而无需访问它作为一个联盟?(How to sto

2019-09-22 14:24发布

我想优化的代码基本上是一个简单的,但大的算术公式,它应该是自动分析代码来计算并行的独立乘法/加法相当简单,但我读了自动向量化只适用于循环。

我读过多次,现在单个元素的矢量通过工会或其他方式的访问应该不惜一切代价避免,而是应该由_mm_shuffle_pd(我只有努力双打)所取代......

我似乎没有搞清楚我如何才能__m128d向量作为双打的内容存储,而无需访问它作为一个工会。 此外,没有比标量代码时,这样的操作给任何的性能提升?

union {
  __m128d v;
  double d[2];
} vec;
union {
  __m128d v;
double d[2];
} vec2;

vec.v = index1;
vec2.v = index2;
temp1 = _mm_mul_pd(temp1, _mm_set_pd(bvec[vec.d[1]], bvec[vec2[1]]));

同时,这两个工会看起来可笑的难看,但使用时

union dvec {
  __m128d v;
  double d[2];
} vec;

试图声明indexX为dvec,编译器抱怨dvec是未申报。

Answer 1:

不幸的是,如果你看一下MSDN它说以下内容:

不应该 直接 访问 __m128d领域。 你可以,但是,看到在调试器中这些类型。 类型的变量__m128映射到XMM [0-7]寄存器。

我在SIMD不是专家,但是这告诉我,你在做什么,因为它只是没有设计将无法工作。

编辑:

我刚刚发现了这个 ,和它说:

只有在赋值的左侧使用__m128,__m128d和__m128i,作为返回值,或者作为一个参数。 不要在其它算术表达式,如“+”,并用它“>>”。

它还说:

使用__m128,__m128d和__m128i以聚集体的对象,如联盟(例如,访问所述浮子元件)和结构。

因此,也许你可以使用它们,但只有在工会。 似乎有矛盾什么的MSDN说,但是。

EDIT2:

下面是关于如何使用这些SIMD类型的例子描述了另一个有趣的资源

在上面的链接,你会发现这条线:

#include <math.h>
#include <emmintrin.h>
double in1_min(__m128d x)
{
    return x[0];
}

在上面我们使用GCC 4.6新的扩展通过索引来访问高低部分。 GCC的旧版本需要使用工会和写作两个双打的数组。 当优化关闭这很麻烦,而且更慢。



Answer 2:

_mm_cvtsd_f64 + _mm_unpackhi_pd

双打:

#include <assert.h>

#include <x86intrin.h>

int main(void) {
    __m128d x = _mm_set_pd(1.5, 2.5);
    /* _mm_cvtsd_f64 + _mm_unpackhi_pd */
    assert(_mm_cvtsd_f64(x) == 2.5);
    assert(_mm_cvtsd_f64(_mm_unpackhi_pd(x, x)) == 1.5);
}

对于花车,我已经张贴在下面的例子如何为十六进制浮点转换为C / C的浮动++使用_mm_extract_ps SSE GCC instrinc功能

  • _mm_cvtss_f32 + _mm_shuffle_ps
  • _MM_EXTRACT_FLOAT

对于整型,你可以使用_mm_extract_epi32

#include <assert.h>

#include <x86intrin.h>

int main(void) {
    __m128i x = _mm_set_epi32(1, 2, 3, 4);
    assert(_mm_extract_epi32(x, 3) == 4);
    assert(_mm_extract_epi32(x, 2) == 3);
    assert(_mm_extract_epi32(x, 1) == 1);
    assert(_mm_extract_epi32(x, 0) == 1);
}

GitHub的上游 。

编译和运行示例:

gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -pedantic -o main.out main.c
./main.out

经测试在Ubuntu 19.04 AMD64。



Answer 3:

有一个双_mm_cvtsd_f64(__m128d a)以“emmintrin.h”定义为访问两个双打的SSE矢量的下部双重功能。

从英特尔内部函数指南:

概要

  • 双_mm_cvtsd_f64(__m128d一个)
  • 包括“emmintrin.h”
  • 说明:MOVSD
  • CPUID功能标志:SSE2

说明 :复制下部双精度(64位)的浮点数元件DST。

操作DST [63:0]:= A [63:0]



文章来源: How to store the contents of a __m128d simd vector as doubles without accessing it as a union?