我在哪里可以找到有关常见SIMD技巧的信息?我有一个指令集,知道如何编写非棘手的SIMD代码,但我知道,SIMD现在功能更强大.它可以保存复杂的条件无分支代码.
例如(ARMv6),以下指令序列将Rd的每个字节设置为等于Ra和Rb的相应字节的无符号最小值:
USUB8 Rd, Ra, Rb
SEL Rd, Rb, Ra
教程/非常见SIMD技术的链接也很好:) ARMv6对我来说是最有趣的,但x86(SSE,...)/ Neon(在ARMv7中)/其他也很好.
我想添加一个SSE寄存器的四个组件来获得一个浮点数.这是我现在这样做的方式:
float a[4];
_mm_storeu_ps(a, foo128);
float x = a[0] + a[1] + a[2] + a[3];
是否有直接实现此目的的SSE指令?
我目前正在开发一个开源的3D应用程序框架的C++(用C++ 11).我自己的数学库的设计类似于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);
或者编译器应该做脏工作吗?
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];
或者我应该使用SIMD和其他代码吗?就像具有SIMD操作的动态容器类一样,需要额外的load和store指令.
Pear3D::Vector4f* v1 = new Pear3D::Vector4f(0.5f, …我正在阅读英特尔的内在指南,同时实现SIMD支持.我有一些困惑,我的问题如下.
__m128 _mm_cmpeq_ps (__m128 a, __m128 b)文档说它用于比较打包的单精度浮点数."打包"是什么意思?在使用它们之前,我是否需要以某种方式打包我的浮动值?
对于双精度,有内在函数,比如_mm_cmpeq_sd"比较"双精度浮点元素.低和高双精度elemtns是什么意思?我可以使用它们来比较C++ double类型元素的向量吗?或者在比较之前我是否需要以某种方式处理它们?
不同类型的逻辑SSE内在函数之间有什么区别吗?例如,如果我们采用OR运算,有三个内在函数:_mm_or_ps,_mm_or_pd和_mm_or_si128所有这些都做同样的事情:计算其操作数的按位 OR.我的问题:
使用一个或另一个内在(使用适当的类型转换)之间是否有任何区别.在某些特定情况下,是否会有更长的执行等隐藏成本?
这些内在函数映射到三个不同的x86指令(por,orps,orpd).有没有人有任何想法为什么英特尔浪费宝贵的操作码空间的几个指令做同样的事情?
以下两行有什么区别?
__m128 x = _mm_load_ps((float *) ptr);
__m128 y = _mm_load_pd((double *)ptr);
换句话说,为什么有这么多不同的_mm_load_xyz指令,而不是通用的__m128 _mm_load(const void *)?
假设我想添加两个缓冲区并存储结果.两个缓冲区已经分配了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 );
  }
}
第二个例子直接在内存地址上执行了添加操作,没有加载/存储操作.两缝都很好.
void _add( uint16_t * dst, uint16_t const * src, size_t n )
{
  for( uint16_t const * end( dst + n …在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:
  // …我有一个四个64位浮点值的打包向量.
我想得到向量元素的总和.
使用SSE(并使用32位浮点数),我可以执行以下操作:
v_sum = _mm_hadd_ps(v_sum, v_sum);
v_sum = _mm_hadd_ps(v_sum, v_sum);
不幸的是,即使AVX具有_mm256_hadd_pd指令,它的结果也与SSE版本不同.我相信这是因为大多数AVX指令分别用作每个低128位和高128位的SSE指令,而不会跨越128位边界.
理想情况下,我要寻找的解决方案应遵循以下准则:
1)仅使用AVX/AVX2指令.(没有SSE)
2)不超过2-3条指令.
但是,任何有效/优雅的方式(即使不遵循上述指导原则)总是被广泛接受.
非常感谢您的帮助.
-Luigi Castelli
我正在运行一些使用的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");
生产:
16 bytes per operation
4 floats per operation
4 ints per operation
2 doubles per operation
我哪里错了?要查看所有项目设置等,可在此处获得该项目.