标签: sse

混合SSE整数/浮点SIMD指令时,是否会降低性能?

我最近以内在函数的形式使用了x86 SIMD指令(SSE1234).我发现令人沮丧的是,SSE ISA有几个简单的指令,只能用于浮点数或仅用于整数,但理论上它们应该同样适用于两者.例如,float和double向量都有指令从地址(movhps,movhpd)加载更高的64位128位向量,但是没有这样的整数向量指令.

我的问题:

在整数向量上使用浮点指令时是否有任何理由期望性能受到影响,例如使用movhps将数据加载到整数向量?

我写了几个测试来检查,但我认为他们的结果不可信.编写一个正确的测试来探索这些事情的所有极端情况真的很难,特别是在这里可能涉及指令调度时.

相关问题:

其他平凡相似的东西也有几个基本相同的指令.例如,我可以使用por,orpsorpd按位OR .任何人都可以解释这些附加说明的目的是什么?我想这可能与应用于每条指令的不同调度算法有关.

c assembly sse simd intrinsics

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

添加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万
查看次数

为什么一些SSE"mov"指令指定它们移动浮点值?

许多SSE"mov"指令指定它们正在移动浮点值.例如:

  • MOVHLPS-移动填充单精度浮点值从高到低
  • MOVSD-移动标量双精度浮点值
  • MOVUPD-移动未对齐的双精度浮点值

为什么这些指令只是说它们移动32位或64位值?如果它们只是移动位,为什么指令指定它们是浮点值?当然,无论你是否将这些位解释为浮点,它们都能工作吗?

x86 assembly sse

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

如何实现"_mm_storeu_epi64"没有别名问题?

(注意:虽然这个问题是关于"存储"的,但"加载"情况具有相同的问题并且是完全对称的.)

SSE内在函数提供_mm_storeu_pd具有以下签名的函数:

void _mm_storeu_pd (double *p, __m128d a);
Run Code Online (Sandbox Code Playgroud)

所以,如果我有两个双精度矢量,并且我想将它存储到两个双精度数组中,我可以使用这个内在函数.

但是,我的矢量不是两个双打; 它是两个64位整数,我想将它存储到两个64位整数的数组中.也就是说,我想要一个具有以下签名的函数:

void _mm_storeu_epi64 (int64_t *p, __m128i a);
Run Code Online (Sandbox Code Playgroud)

但内在函数没有提供这样的功能.他们最接近的是_mm_storeu_si128:

void _mm_storeu_si128 (__m128i *p, __m128i a);
Run Code Online (Sandbox Code Playgroud)

问题是这个函数需要一个指针__m128i,而我的数组是一个数组int64_t.通过错误类型的指针写入对象违反了严格的别名,并且肯定是未定义的行为.我担心我的编译器现在或将来会重新排序或以其他方式优化存储,从而以奇怪的方式破坏我的程序.

要清楚,我想要的是一个我可以这样调用的函数:

__m128i v = _mm_set_epi64x(2,1);
int64_t ra[2];
_mm_storeu_epi64(&ra[0], v); // does not exist, so I want to implement it
Run Code Online (Sandbox Code Playgroud)

以下是创建此类功能的六次尝试.

尝试#1

void _mm_storeu_epi64(int64_t *p, __m128i a) {
    _mm_storeu_si128(reinterpret_cast<__m128i *>(p), a);
}
Run Code Online (Sandbox Code Playgroud)

这似乎有我担心的严格别名问题.

尝试#2

void _mm_storeu_epi64(int64_t *p, __m128i a) {
    _mm_storeu_si128(static_cast<__m128i *>(static_cast<void *>(p)), a);
}
Run Code Online (Sandbox Code Playgroud)

一般来说可能更好 …

c++ sse strict-aliasing intrinsics

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

如何使用SSE指令集绝对2双或4浮点数?(截至SSE4)

这是我尝试使用SSE加速的示例C代码,两个数组是3072元素长的双精度数,如果我不需要双精度,可以将其下放到浮点数.

double sum = 0.0;

for(k = 0; k < 3072; k++) {
    sum += fabs(sima[k] - simb[k]);
}

double fp = (1.0 - (sum / (255.0 * 1024.0 * 3.0)));
Run Code Online (Sandbox Code Playgroud)

无论如何,我目前的问题是如何在SSE寄存器中执行fabs步骤为double或float,以便我可以将整个计算保留在SSE寄存器中,以便它保持快速,并且我可以通过部分展开此循环来并行化所有步骤.

这里有一些资源我发现了fabs()asm或者可能会翻转这个标志 -但是第二个的弱点需要有条件的检查.

gcc sse

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

在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
查看次数

告诉C++指针数据是16字节对齐的

我用静态数组编写了一些代码,它的矢量化很好.

float data[1024] __attribute__((aligned(16)));
Run Code Online (Sandbox Code Playgroud)

我想动态分配数组.我尝试过这样的事情:

float *data = (float*) aligned_alloc(16, size*sizeof(float));
Run Code Online (Sandbox Code Playgroud)

但是编译器(GCC 4.9.2)不再能够对代码进行矢量化.我假设这是因为它不知道指针数据是16字节对齐的.我得到的消息如下:

note: Unknown alignment for access: *_43
Run Code Online (Sandbox Code Playgroud)

我尝试在使用数据之前添加此行,但它似乎没有做任何事情:

data = (float*) __builtin_assume_aligned(data, 16);
Run Code Online (Sandbox Code Playgroud)

使用不同的变量并restrict没有帮助:

float* __restrict__ align_data = (float*) __builtin_assume_aligned(data,16);
Run Code Online (Sandbox Code Playgroud)

例:

#include <iostream>
#include <stdlib.h>
#include <math.h>

#define SIZE 1024
#define DYNAMIC 0
#define A16 __attribute__((aligned(16)))
#define DA16 (float*) aligned_alloc(16, size*sizeof(float))

class Test{
public:
    int size;
#if DYNAMIC
    float *pos;
    float *vel;
    float *alpha;
    float *k_inv;
    float *osc_sin;
    float *osc_cos;
    float *dosc1;
    float *dosc2;
#else
    float …
Run Code Online (Sandbox Code Playgroud)

c++ gcc sse memory-alignment

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