标签: simd

常见的SIMD技术

我在哪里可以找到有关常见SIMD技巧的信息?我有一个指令集,知道如何编写非棘手的SIMD代码,但我知道,SIMD现在功能更强大.它可以保存复杂的条件无分支代码.
例如(ARMv6),以下指令序列将Rd的每个字节设置为等于Ra和Rb的相应字节的无符号最小值:

USUB8 Rd, Ra, Rb
SEL Rd, Rb, Ra
Run Code Online (Sandbox Code Playgroud)

教程/非常见SIMD技术的链接也很好:) ARMv6对我来说是最有趣的,但x86(SSE,...)/ Neon(在ARMv7中)/其他也很好.

arm sse simd neon mmx

17
推荐指数
2
解决办法
2519
查看次数

添加SSE寄存器的组件

我想添加一个SSE寄存器的四个组件来获得一个浮点数.这是我现在这样做的方式:

float a[4];
_mm_storeu_ps(a, foo128);
float x = a[0] + a[1] + a[2] + a[3];
Run Code Online (Sandbox Code Playgroud)

是否有直接实现此目的的SSE指令?

c++ floating-point sse simd addition

17
推荐指数
1
解决办法
3216
查看次数

我应该使用SIMD或矢量扩展还是别的?

我目前正在开发一个开源的3D应用程序框架(用).我自己的数学库的设计类似于XNA数学库,同时考虑了SIMD.但目前它并不是很快,而且它在内存中存在问题,但在另一个问题上更多.

几天前我问自己为什么要编写自己的SSE代码.编译器还可以在启用优化时生成高优化代码.我也可以使用GCC的" 向量扩展 " .但这一切都不是真正的便携式.

我知道当我使用自己的SSE代码时,我有更多的控制权,但通常这种控制是不公平的.

SSE的一个大问题是使用动态内存,这在内存池和面向数据的设计的帮助下,尽可能地受到限制.

现在问我的问题:

  • 我应该使用裸SSE吗?也许是封装的.

    __m128 v1 = _mm_set_ps(0.5f, 2, 4, 0.25f);
    __m128 v2 = _mm_set_ps(2, 0.5f, 0.25f, 4);
    
    __m128 res = _mm_mul_ps(v1, v2);
    
    Run Code Online (Sandbox Code Playgroud)
  • 或者编译器应该做脏工作吗?

    float v1 = {0.5f, 2, 4, 0.25f};
    float v2 = {2, 0.5f, 0.25f, 4};
    
    float res[4];
    res[0] = v1[0]*v2[0];
    res[1] = v1[1]*v2[1];
    res[2] = v1[2]*v2[2];
    res[3] = v1[3]*v2[3];
    
    Run Code Online (Sandbox Code Playgroud)
  • 或者我应该使用SIMD和其他代码吗?就像具有SIMD操作的动态容器类一样,需要额外的loadstore指令.

    Pear3D::Vector4f* v1 = new Pear3D::Vector4f(0.5f, …
    Run Code Online (Sandbox Code Playgroud)

c++ gcc sse simd

17
推荐指数
1
解决办法
1万
查看次数

SIMD和打包和标量双精度之间的区别

我正在阅读英特尔的内在指南,同时实现SIMD支持.我有一些困惑,我的问题如下.

  1. __m128 _mm_cmpeq_ps (__m128 a, __m128 b)文档说它用于比较打包的单精度浮点数."打包"是什么意思?在使用它们之前,我是否需要以某种方式打包我的浮动值?

  2. 对于双精度,有内在函数,比如_mm_cmpeq_sd"比较"双精度浮点元素.低和高双精度elemtns是什么意思?我可以使用它们来比较C++ double类型元素的向量吗?或者在比较之前我是否需要以某种方式处理它们?

c++ x86 sse simd intrinsics

17
推荐指数
2
解决办法
8718
查看次数

逻辑SSE内在函数之间有什么区别?

不同类型的逻辑SSE内在函数之间有什么区别吗?例如,如果我们采用OR运算,有三个内在函数:_mm_or_ps,_mm_or_pd和_mm_or_si128所有这些都做同样的事情:计算其操作数的按位 OR.我的问题:

  1. 使用一个或另一个内在(使用适当的类型转换)之间是否有任何区别.在某些特定情况下,是否会有更长的执行等隐藏成本?

  2. 这些内在函数映射到三个不同的x86指令(por,orps,orpd).有没有人有任何想法为什么英特尔浪费宝贵的操作码空间的几个指令做同样的事情?

c sse simd intrinsics sse2

16
推荐指数
3
解决办法
3605
查看次数

在Intel x86 ISA上_mm_load_ps与_mm_load_pd vs. etc

以下两行有什么区别?

__m128 x = _mm_load_ps((float *) ptr);
__m128 y = _mm_load_pd((double *)ptr);
Run Code Online (Sandbox Code Playgroud)

换句话说,为什么有这么多不同的_mm_load_xyz指令,而不是通用的__m128 _mm_load(const void *)

c x86 sse intel simd

16
推荐指数
2
解决办法
5418
查看次数

SSE:_mm_load/store与使用直接指针访问之间的区别

假设我想添加两个缓冲区并存储结果.两个缓冲区已经分配了16byte对齐.我找到了两个如何做到这一点的例子.

第一个是使用_mm_load将数据从缓冲区读入SSE寄存器,执行add操作并存储回结果寄存器.到现在为止,我会这样做.

void _add( uint16_t * dst, uint16_t const * src, size_t n )
{
  for( uint16_t const * end( dst + n ); dst != end; dst+=8, src+=8 )
  {
    __m128i _s = _mm_load_si128( (__m128i*) src );
    __m128i _d = _mm_load_si128( (__m128i*) dst );

    _d = _mm_add_epi16( _d, _s );

    _mm_store_si128( (__m128i*) dst, _d );
  }
}
Run Code Online (Sandbox Code Playgroud)

第二个例子直接在内存地址上执行了添加操作,没有加载/存储操作.两缝都很好.

void _add( uint16_t * dst, uint16_t const * src, size_t n )
{
  for( uint16_t const * end( dst + n …
Run Code Online (Sandbox Code Playgroud)

x86 sse simd

16
推荐指数
2
解决办法
6019
查看次数

如何从预取内在函数中获得可衡量的好处?

在x86_64上使用gcc 4.4.5(是的......我知道它已经老了).出于兼容性原因,仅限于SSE2(或更早)的说明.

我认为应该是一个教科书案例,以获得预取的巨大好处.我有一个32位元素的数组("A"),它不是(也可能不是)按顺序排列的.这些32位元素是__m128i数据的较大数据数组("D")的索引.为"A"的各要素,我需要在"d"从适当的位置取__m128i数据,在其上执行的操作,并且将其存储回在"d"的相同位置.实际上D中的每个"条目"都是"SOME_CONST"__m128i的大.因此,如果A中的值为"1",则D中的索引为D [1*SOME_CONST].

由于"A"中的连续元素几乎不会指向"D"中的连续位置,因此我倾向于认为硬件预取器将会挣扎或无法完成任何有用的操作.

但是,我可以很容易地预测下一个我将要访问的位置,只需在"A"中向前看即可.足够的措辞......这里有一些代码.我对数据执行的操作是取__m128i的低64位并将其克隆到相同的高64位.首先是基本循环,没有多余的装饰......

// SOME_CONST is either 3 or 4, but this "operation" only needs to happen for 3

for ( i=0; i<arraySize; ++i )
{
  register __m128i *dPtr = D + (A[i] * SOME_CONST);
  dPtr[0] = _mm_shuffle_epi32( dPtr[0], 0 | (1<<2) | (0<<4) | (1<<6) );
  dPtr[1] = _mm_shuffle_epi32( dPtr[1], 0 | (1<<2) | (0<<4) | (1<<6) );
  dPtr[2] = _mm_shuffle_epi32( dPtr[2], 0 | (1<<2) | (0<<4) | (1<<6) );

  // The immediate operand selects:
  // …
Run Code Online (Sandbox Code Playgroud)

performance sse x86-64 simd prefetch

16
推荐指数
1
解决办法
649
查看次数

使用AVX指令进行水平矢量和的最快方法

我有一个四个64位浮点值的打包向量.
我想得到向量元素的总和.

使用SSE(并使用32位浮点数),我可以执行以下操作:

v_sum = _mm_hadd_ps(v_sum, v_sum);
v_sum = _mm_hadd_ps(v_sum, v_sum);
Run Code Online (Sandbox Code Playgroud)

不幸的是,即使AVX具有_mm256_hadd_pd指令,它的结果也与SSE版本不同.我相信这是因为大多数AVX指令分别用作每个低128位和高128位的SSE指令,而不会跨越128位边界.

理想情况下,我要寻找的解决方案应遵循以下准则:
1)仅使用AVX/AVX2指令.(没有SSE)
2)不超过2-3条指令.

但是,任何有效/优雅的方式(即使不遵循上述指导原则)总是被广泛接受.

非常感谢您的帮助.

-Luigi Castelli

x86 sse simd vector-processing avx

15
推荐指数
1
解决办法
2万
查看次数

RyuJIT没有充分利用SIMD内在函数

我正在运行一些使用的C#代码,System.Numerics.Vector<T>但据我所知,我没有得到SIMD内在函数的全部好处.我正在使用Visual Studio Community 2015和Update 1,而我的clrjit.dll是v4.6.1063.1.

我正在使用英特尔酷睿i5-3337U处理器,它实现了AVX指令集扩展.因此,我想,我应该能够在256位寄存器上执行大多数SIMD指令.例如,拆卸中应包含的指令vmovups,vmovupd,vaddups,等...,并且Vector<float>.Count应该返回8,Vector<double>.Count应该是4,等等......但是,这不是我所看到的.

相反,我的拆卸包含指令等movups,movupd,addups等...以下代码:

WriteLine($"{Vector<byte>.Count} bytes per operation");
WriteLine($"{Vector<float>.Count} floats per operation");
WriteLine($"{Vector<int>.Count} ints per operation");
WriteLine($"{Vector<double>.Count} doubles per operation");
Run Code Online (Sandbox Code Playgroud)

生产:

16 bytes per operation
4 floats per operation
4 ints per operation
2 doubles per operation
Run Code Online (Sandbox Code Playgroud)

我哪里错了?要查看所有项目设置等,可在此处获得该项目.

c# sse simd avx ryujit

15
推荐指数
1
解决办法
1428
查看次数

标签 统计

simd ×10

sse ×10

x86 ×4

c++ ×3

avx ×2

c ×2

intrinsics ×2

addition ×1

arm ×1

c# ×1

floating-point ×1

gcc ×1

intel ×1

mmx ×1

neon ×1

performance ×1

prefetch ×1

ryujit ×1

sse2 ×1

vector-processing ×1

x86-64 ×1