6

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

我现在已经读过很多次了,应该不惜一切代价避免通过联合或其他方式访问向量中的单个元素,而应该用 _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 未声明。

4

3 回答 3

7

不幸的是,如果您查看 MSDN,它会显示以下内容:

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

我不是 SIMD 方面的专家,但这告诉我你正在做的事情不会起作用,因为它不是设计的。

编辑:

我刚刚找到这个,它说:

仅在赋值的左侧使用 __m128、__m128d 和 __m128i,作为返回值或参数。不要在“+”和“>>”等其他算术表达式中使用它。

它还说:

在聚合中使用 __m128、__m128d 和 __m128i 对象,例如联合(例如,访问浮点元素)和结构。

所以也许你可以使用它们,但只能在工会中使用。然而,这似乎与 MSDN 所说的相矛盾。

编辑2:

这是另一个有趣的资源,它通过示例描述了如何使用这些 SIMD 类型

在上面的链接中,你会发现这一行:

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

在上面我们使用 gcc 4.6 中的一个新扩展来通过索引访问高和低部分。旧版本的 gcc 需要使用联合并写入两个双精度数组。这很麻烦,并且在关闭优化时会特别慢。

于 2012-09-19T13:22:25.677 回答
1

_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);
}

对于浮点数,我在How to convert a hex float to a float in C/C++ using _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 上测试。

于 2019-06-01T06:35:28.793 回答
0

在“emmintrin.h”中定义了一个 double _mm_cvtsd_f64 (__m128d a) 函数来访问两个双精度的 sse 向量的低双精度。

从英特尔内部指南:

概要

  • 双 _mm_cvtsd_f64 (__m128d a)
  • 包括“emmintrin.h”
  • 指令:movsd
  • CPUID 功能标志:SSE2

说明:将 a 的低位双精度(64 位)浮点元素复制到 dst。

操作 dst[63:0] := a[63:0]

于 2013-09-27T13:35:39.343 回答