标签: simd

将两个x86 32位寄存器存储到128位xmm寄存器中

有没有更快的方法在一个128位xmm寄存器中存储两个x86 32位寄存器?

  movd  xmm0, edx
  movd  xmm1, eax
  pshufd xmm0, xmm0, $1
  por   xmm0, xmm1 
Run Code Online (Sandbox Code Playgroud)

因此,如果EAX为0x12345678且EDX为0x87654321,则xmm0中的结果必须为0x8765432112345678.

谢谢

x86 assembly sse simd

9
推荐指数
1
解决办法
3100
查看次数

SSE比FPU慢?

我有一大段代码,其中一部分包含这段代码:

result = (nx * m_Lx + ny * m_Ly + m_Lz) / sqrt(nx * nx + ny * ny + 1);
Run Code Online (Sandbox Code Playgroud)

我已经矢量化如下(一切都已经是float):

__m128 r = _mm_mul_ps(_mm_set_ps(ny, nx, ny, nx),
                      _mm_set_ps(ny, nx, m_Ly, m_Lx));
__declspec(align(16)) int asInt[4] = {
    _mm_extract_ps(r,0), _mm_extract_ps(r,1),
    _mm_extract_ps(r,2), _mm_extract_ps(r,3)
};
float (&res)[4] = reinterpret_cast<float (&)[4]>(asInt);
result = (res[0] + res[1] + m_Lz) / sqrt(res[2] + res[3] + 1);
Run Code Online (Sandbox Code Playgroud)

结果是正确的; 但是,我的基准测试显示矢量化版本较慢:

  • 非矢量化版本需要3750毫秒
  • 矢量化版本需要4050毫秒
  • 设置result0直接(和完全除去这部分代码)降低了整个过程至2500毫秒

鉴于矢量版本只包含一个集SSE乘法(而不是四个单独的FPU乘法)的,为什么会慢?FPU确实比SSE快,或者这里有混淆变量吗?

(我在移动Core i5上.)

c++ optimization sse simd vectorization

9
推荐指数
1
解决办法
3514
查看次数

Constexpr和SSE内在函数

大多数C++编译器都支持SIMD(SSE/AVX)指令

_mm_cmpeq_epi32
Run Code Online (Sandbox Code Playgroud)

我的问题是这个函数没有标记为constexpr,虽然"语义上"没有理由不使用这个函数,constexpr因为它是一个纯函数.

有什么办法,我可以写我自己的版本(例如)_mm_cmpeq_epi32constexpr

显然我希望运行时的函数使用正确的asm,我知道我可以重新实现具有慢速函数的任何SIMD函数constexpr.

如果你想知道为什么我关心constexprSIMD功能.非constexprness具有传染性,这意味着我的任何使用SIMD功能的功能都不可能constexpr.

c++ sse simd intrinsics constexpr

9
推荐指数
1
解决办法
721
查看次数

将散点索引转换为聚集索引的有效方法?

我正在尝试使用SIMD内在函数编写流压缩(获取数组并删除空元素).循环的每次迭代一次处理8个元素(SIMD宽度).

使用SSE内在函数,我可以使用_mm_shuffle_epi8()进行相当有效的操作,它执行16条表查找(收集并行计算术语).shuffle索引是预先计算的,并使用位掩码查找.

for (i = 0; i < n; i += 8)
{
  v8n_Data = _mm_load_si128(&data[i]);
  mask = _mm_movemask_epi8(&is_valid[i]) & 0xff;     // is_valid is byte array
  v8n_Compacted = _mm_shuffle_epi8(v16n_ShuffleIndices[mask]);
  _mm_storeu_si128(&compacted[count], v8n_Compacted);

  count += bitCount[mask];
}
Run Code Online (Sandbox Code Playgroud)

我的问题是现在我想为Altivec SIMD实现这个(不要问为什么 - 错误的商业决策).Altivec没有_mm_movemask_epi8()的等价物,这是一个关键因素.所以,我需要找到一种方法

  1. 模拟_mm_movemask_epi8() - 似乎很贵,有几个班次和OR

  2. 直接生成有效的shuffle指数 -

即,索引i将是未压缩数据中第i个有效元素的索引

element_valid:   0 0 1 0 1 0 0 1 0
gather_indices:  x x x x x x 6 4 1
scatter_indices: 3 3 2 2 1 1 1 0 0
Run Code Online (Sandbox Code Playgroud)

串行执行此操作非常简单,但我需要它是并行(SIMD).使用前缀sum生成散列索引似乎很容易,但由于AltiVec和SSE都没有散点指令,我需要收集索引.收集索引是散射指数的反函数,但是如何并行获得?我知道在GPU编程的开创性时代,将散射转换为收集是一种常见的技术,但这两种方法中没有一种看似实用.

也许如果不坚持压缩保留元素顺序将允许更有效的实现?我可以放弃.

sse simd vectorization altivec stream-compaction

8
推荐指数
1
解决办法
2081
查看次数

SSE2指令以相反的顺序加载整数

是否有任何SSE2指令以相反的顺序intint缓冲区加载128位向量寄存器?

x86 sse simd sse2

8
推荐指数
1
解决办法
4014
查看次数

在C(SIMD)中快速转换图像和Sobel滤波器优化

我想为我和我的朋友写一个真正(非常)快速的Sobel算子用于射线追踪器(可以在这里找到源码).以下是我到目前为止所得到的......

首先,假设图像是8位无符号整数数组中逐行的灰度图像存储.

要编写真正的Sobel滤波器,我需要为每个像素计算Gx和Gy.由于原点旁边有6个像素,因此计算出这些数字中的每一个.但SIMD指令允许我处理16或甚至32(AVX)像素.希望运算符的内核具有一些不错的属性,因此我可以通过以下方式计算Gy:

  • 减去每个i和i + 2行并将结果存储在某个其他图片(数组)的i + 1行中
  • 添加i,i + 1和i + 2列的两倍给出最终图片的i + 1列

我会做同样的(但转置)计算Gx然后添加两张图片.

一些说明:

  • 我不关心内存分配,因为一切都将在开始时分配.
  • 我可以处理溢出并签署将值除以4的问题(感谢_mm_srli_epi8) (uint8_t >> 2 - uint8_t >> 2) = int7_t //really store as int8_t
    int7_t + uint8_t << 1 >> 2 + int7_t = uint8_t
    //some precision is lost but I don't care

我面临的真正问题是从行到列.因为我无法将图片加载到SIMD寄存器中.我必须三次翻转图像至少不是吗?

一旦原始图片.然后我可以计算Gx和Gy的第一步,然后翻转结果图片以计算第二步.

所以,这是我的问题:

  • 这种实现是一个好主意吗?
  • 有没有办法比dumb算法更快地转置数组?(我不这么认为)
  • 瓶颈在哪里?(有什么猜测?:P)

c optimization sse simd

8
推荐指数
1
解决办法
3898
查看次数

在SSE __m128i寄存器中置换字节

我有以下问题:

__m128i寄存器中,按以下顺序排列有16个8位值:

[ 1, 5, 9, 13 ] [ 2, 6, 10, 14] [3, 7, 11, 15]  [4, 8, 12, 16]
Run Code Online (Sandbox Code Playgroud)

我想要实现的是有效地改组字节以获得这种排序:

[ 1, 2, 3, 4 ] [ 5, 6, 7, 8] [9, 10, 11, 12]  [13, 14, 15, 16]
Run Code Online (Sandbox Code Playgroud)

它实际上类似于4x4矩阵转置,但在一个寄存器内的8位元件上运行.

您能不能指出哪种SSE(优先<= SSE2)指令适合实现这一点?

optimization sse simd

8
推荐指数
1
解决办法
1091
查看次数

Haskell是否自动执行SIMD优化?

可以使用https://hackage.haskell.org/package/ghc-prim-0.4.0.0/docs/GHC-Prim.html#g:28在Haskell中编写基于SIMD的矢量库,但它是否有意义?我在Haskell中发现了几篇致力于自动SIMD优化的论文,但目前的状况是什么(2014年)?例如,https: //hackage.haskell.org/package/vector是否使用SIMD,或者最好使用低级SIMD原语手动编写优化库?

haskell simd

8
推荐指数
2
解决办法
1033
查看次数

如何同时使用omp parallel和omp simd?

我想测试#pragma omp parallel for#pragma omp simd一个简单的矩阵追加程序.当我单独使用它们时,我没有错误,看起来很好.但是,我想测试使用它们可以获得多少性能.如果我#pragma omp parallel for在外循环#pragma omp simd之前和内循环之前使用,我也没有错误.当我在外部循环之前使用它们时发生错误.我在运行时遇到错误而不是编译时间.ICCGCC返回错误,但Clang没有.这可能是因为Clang重新定位了并行化.在我的实验中,Clang没有并行化并只用一个线程运行程序.

该计划在这里:

#include <stdio.h>
//#include <x86intrin.h>
#define N 512
#define M N

int __attribute__(( aligned(32))) a[N][M],
    __attribute__(( aligned(32))) b[N][M],
    __attribute__(( aligned(32))) c_result[N][M];

int main()
{
    int i, j;
    #pragma omp parallel for
    #pragma omp simd
    for( i=0;i<N;i++){
        for(j=0;j<M;j++){
            c_result[i][j]= a[i][j] + b[i][j];
        }
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

错误:ICC:

IMP1.c(20):错误:omp指令后面没有可并行化的for循环#pragma omp parallel for ^

IMP1.c的编译中止(代码2) …

c parallel-processing x86 simd openmp

8
推荐指数
1
解决办法
2538
查看次数

如何使用 SIMD 计算字符出现次数

我得到了一个小写字符数组(最多 1.5Gb)和一个字符 c。我想使用 AVX 指令查找字符 c 出现了多少次。

    unsigned long long char_count_AVX2(char * vector, int size, char c){
    unsigned long long sum =0;
    int i, j;
    const int con=3;
    __m256i ans[con];
    for(i=0; i<con; i++)
        ans[i]=_mm256_setzero_si256();

    __m256i Zer=_mm256_setzero_si256();
    __m256i C=_mm256_set1_epi8(c);
    __m256i Assos=_mm256_set1_epi8(0x01);
    __m256i FF=_mm256_set1_epi8(0xFF);
    __m256i shield=_mm256_set1_epi8(0xFF);
    __m256i temp;
    int couter=0;
    for(i=0; i<size; i+=32){
        couter++;
        shield=_mm256_xor_si256(_mm256_cmpeq_epi8(ans[0], Zer), FF);
        temp=_mm256_cmpeq_epi8(C, *((__m256i*)(vector+i)));
        temp=_mm256_xor_si256(temp, FF);
        temp=_mm256_add_epi8(temp, Assos);
        ans[0]=_mm256_add_epi8(temp, ans[0]);
        for(j=1; j<con; j++){
            temp=_mm256_cmpeq_epi8(ans[j-1], Zer);
            shield=_mm256_and_si256(shield, temp);
            temp=_mm256_xor_si256(shield, FF);
            temp=_mm256_add_epi8(temp, Assos);
            ans[j]=_mm256_add_epi8(temp, ans[j]);
        }
    }
    for(j=con-1; j>=0; …
Run Code Online (Sandbox Code Playgroud)

c simd avx avx2

8
推荐指数
1
解决办法
3814
查看次数