标签: simd

使用SSE索引到数组

假设我有一个数组:

uint8_t arr[256];
Run Code Online (Sandbox Code Playgroud)

和一个元素

__m128i x
Run Code Online (Sandbox Code Playgroud)

包含16个字节,

x_1, x_2, ... x_16
Run Code Online (Sandbox Code Playgroud)

我想有效地填补一个新__m128i元素

__m128i y
Run Code Online (Sandbox Code Playgroud)

使用arr取决于值的值x,以便:

y_1  = arr[x_1]
y_2  = arr[x_2]
   .
   .
   .
y_16 = arr[x_16]
Run Code Online (Sandbox Code Playgroud)

实现此目的的命令实质上是从非连续的一组存储器位置加载寄存器.我有一种痛苦的模糊记忆,看过这样一个命令的文档,但现在找不到它.它存在吗?在此先感谢您的帮助.

c sse simd

12
推荐指数
1
解决办法
2161
查看次数

使用带有gcc的SSE指令而不使用内联汇编

我有兴趣使用x86-64与gcc的SSE向量指令,并且不想为此使用任何内联汇编.有没有办法在C中做到这一点?如果是这样,有人可以举个例子吗?

c gcc sse x86-64 simd

12
推荐指数
3
解决办法
8834
查看次数

SIMD以下代码

如何在C中简化以下代码(当然使用SIMD内在函数)?我无法理解SIMD内在函数,这会有很大帮助:

int sum_naive( int n, int *a )
{
    int sum = 0;
    for( int i = 0; i < n; i++ )
        sum += a[i];
    return sum;
}
Run Code Online (Sandbox Code Playgroud)

c x86 sse simd

12
推荐指数
1
解决办法
6187
查看次数

快速矢量化rsqrt和SSE/AVX的倒数取决于精度

假设有必要计算打包浮点数据的倒数或倒数平方根.两者都可以轻松完成:

__m128 recip_float4_ieee(__m128 x) { return _mm_div_ps(_mm_set1_ps(1.0f), x); }
__m128 rsqrt_float4_ieee(__m128 x) { return _mm_div_ps(_mm_set1_ps(1.0f), _mm_sqrt_ps(x)); }
Run Code Online (Sandbox Code Playgroud)

这种方法效果很好但很慢:根据指南,它们在Sandy Bridge上进行了14次和28次循环(吞吐量).对应的AVX版本在Haswell上几乎占用相同的时间.

另一方面,可以使用以下版本:

__m128 recip_float4_half(__m128 x) { return _mm_rcp_ps(x); }
__m128 rsqrt_float4_half(__m128 x) { return _mm_rsqrt_ps(x); }
Run Code Online (Sandbox Code Playgroud)

它们只需要一到两个时间周期(吞吐量),从而大大提升了性能.但是,它们非常接近:它们产生的结果相对误差小于1.5*2 ^ -12.鉴于单精度浮点数的机器epsilon是2 ^?24,我们可以说这种近似具有大约一半的精度.

似乎可以添加Newton-Raphson迭代以产生具有精度的结果(可能不像IEEE标准所要求的那样精确),参见GCC,ICC,LLVM上的讨论.理论上,相同的方法可用于双精度值,产生精度或精度或精度.

我有兴趣为float和double数据类型以及所有(half,single,double)精度实现此方法的实现.处理特殊情况(除以零,sqrt(-1),inf/nan等)不是必需的.此外,我不清楚这些例程中的哪一个比普通的IEEE编译解决方案更快,哪个更慢.

以下是对答案的一些小限制,请:

  1. 在代码示例中使用内在函数.程序集依赖于编译器,因此不太有用.
  2. 对函数使用类似的命名约定.
  3. 实现例程,将单个SSE/AVX寄存器包含密集打包的float/double值作为输入.如果有相当大的性能提升,你也可以发布几个寄存器作为输入的例程(两个reg可能是可行的).
  4. 如果两个SSE/AVX版本绝对等于将_mm更改为_mm256,则不要发布它们,反之亦然.

欢迎任何性能评估,测量和讨论.

摘要

以下是具有一次NR迭代的单精度浮点数的版本:

__m128 recip_float4_single(__m128 x) {
  __m128 res = _mm_rcp_ps(x);
  __m128 muls …
Run Code Online (Sandbox Code Playgroud)

performance sse simd avx

12
推荐指数
1
解决办法
4202
查看次数

为什么我在GCC 5和cilk-plus中遇到此编译错误?

由于某种原因,cilk_spawn不适用于x86内在函数.每当我尝试将两者组合在同一函数的主体中时,我都会收到错误.(注意cilk_for工作正常).如果我删除所有SIMD指令,它编译并运行正常.

#include <stdio.h>
#include <x86intrin.h>
#include <math.h>
#include <cilk/cilk.h>

int main()
{
    int w = cilk_spawn sqrt(10);
    __m128i x = _mm_set_epi64x(1, 1);
    x = _mm_add_epi64(x, x);
    cilk_sync;
    printf("%d\n", w);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这是gcc输出:

gcc-4.9 -std=c99 -march=native -fcilkplus -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"main.d" -MT"main.d" -o "main.o" "../main.c"
In file included from /usr/lib/gcc/x86_64-linux-gnu/4.9/include/xmmintrin.h:1258:0,
                 from /usr/lib/gcc/x86_64-linux-gnu/4.9/include/x86intrin.h:31,
                 from ../main.c:2:
../main.c: In function ‘main’:
/usr/lib/gcc/x86_64-linux-gnu/4.9/include/emmintrin.h:581:1: error: inlining failed in call to always_inline ‘_mm_set_epi64x’: function not inlinable
 _mm_set_epi64x (long long __q1, long long …
Run Code Online (Sandbox Code Playgroud)

c gcc simd cilk-plus

12
推荐指数
1
解决办法
1054
查看次数

冲突检测指令如何使循环矢量化变得更容易?

AVX512CD指令系列包括:VPCONFLICT,VPLZCNT和VPBROADCASTM.

关于这些指令的维基百科部分说:

AVX-512冲突检测(AVX-512CD)中的指令旨在帮助有效地计算通常无法安全矢量化的循环中元素的无冲突子集.

有哪些例子表明这些指令在向量化循环中有用?如果答案将包括标量循环及其矢量化对应物将会有所帮助.

谢谢!

x86 simd vectorization intel-mic avx512

12
推荐指数
1
解决办法
1071
查看次数

为什么这个SIMD乘法不比非SIMD乘法快?

让我们假设我们有一个函数,每个函数乘以两个1000000双精度数组.在C/C++中,函数如下所示:

void mul_c(double* a, double* b)
{
    for (int i = 0; i != 1000000; ++i)
    {
        a[i] = a[i] * b[i];
    }
}
Run Code Online (Sandbox Code Playgroud)

编译器生成以下程序集-O2:

mul_c(double*, double*):
        xor     eax, eax
.L2:
        movsd   xmm0, QWORD PTR [rdi+rax]
        mulsd   xmm0, QWORD PTR [rsi+rax]
        movsd   QWORD PTR [rdi+rax], xmm0
        add     rax, 8
        cmp     rax, 8000000
        jne     .L2
        rep ret
Run Code Online (Sandbox Code Playgroud)

从上面的程序集看来,编译器似乎使用了SIMD指令,但每次迭代只会增加一倍.所以我决定在内联汇编中编写相同的函数,在那里我充分利用xmm0寄存器并一次乘以两个双精度:

void mul_asm(double* a, double* b)
{
    asm volatile
    (
        ".intel_syntax noprefix             \n\t"
        "xor    rax, rax                    \n\t"
        "0:                                 \n\t"
        "movupd …
Run Code Online (Sandbox Code Playgroud)

c++ performance assembly simd

12
推荐指数
2
解决办法
1823
查看次数

什么是打包、解包和扩展打包数据

我一直在研究英特尔内部函数,每个函数都处理打包或解包或扩展打包的整数、浮点数或双精度数。

似乎这个问题应该在互联网上的某个地方得到回答,但我根本找不到答案。

那个包装物是什么?

sse simd cpu-architecture avx avx2

12
推荐指数
1
解决办法
2622
查看次数

快速计算__m128i寄存器中的设置位数

我应该计算__m128i寄存器的设置位数.特别是,我应该使用以下方法编写两个能够计算寄存器位数的函数.

  1. 寄存器的设定位总数.
  2. 寄存器的每个字节的设置位数.

是否有可以完全或部分执行上述操作的内在功能?

c c++ sse simd sse2

11
推荐指数
1
解决办法
7469
查看次数

打包和解交错两个__m256寄存器

我有一个行的行数组(~20 cols x~1M行),我需要一次从两个__m256寄存器中提取两列.

...a0.........b0......
...a1.........b1......
// ...
...a7.........b7......
// end first __m256
Run Code Online (Sandbox Code Playgroud)

一个天真的方法是这样做

__m256i vindex = _mm256_setr_epi32(
    0,
    1 * stride,
    2 * stride,
    // ...
    7 * stride);
__m256 colA = _mm256_i32gather_ps(baseAddrColA, vindex, sizeof(float));
__m256 colB = _mm256_i32gather_ps(baseAddrColB, vindex, sizeof(float));
Run Code Online (Sandbox Code Playgroud)

但是,我想知道我是否会通过a0, b0, a1, b1, a2, b2, a3, b3在一个中检索gathera4, b4, ... a7, b7在另一个中获得更好的性能,因为它们在内存中更接近,然后对它们进行反交错.那是:

// __m256   lo = a0 b0 a1 b1 a2 b2 a3 b3 // load proximal elements
// __m256   hi …
Run Code Online (Sandbox Code Playgroud)

c++ x86 simd avx avx2

11
推荐指数
1
解决办法
866
查看次数

标签 统计

simd ×10

sse ×6

c ×5

avx ×3

c++ ×3

x86 ×3

avx2 ×2

gcc ×2

performance ×2

assembly ×1

avx512 ×1

cilk-plus ×1

cpu-architecture ×1

intel-mic ×1

sse2 ×1

vectorization ×1

x86-64 ×1