有没有更快的方法在一个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.
谢谢
我有一大段代码,其中一部分包含这段代码:
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)
结果是正确的; 但是,我的基准测试显示矢量化版本较慢:
result到0直接(和完全除去这部分代码)降低了整个过程至2500毫秒鉴于矢量版本只包含一个集SSE乘法(而不是四个单独的FPU乘法)的,为什么会慢?FPU确实比SSE快,或者这里有混淆变量吗?
(我在移动Core i5上.)
大多数C++编译器都支持SIMD(SSE/AVX)指令
_mm_cmpeq_epi32
Run Code Online (Sandbox Code Playgroud)
我的问题是这个函数没有标记为constexpr,虽然"语义上"没有理由不使用这个函数,constexpr因为它是一个纯函数.
有什么办法,我可以写我自己的版本(例如)_mm_cmpeq_epi32是constexpr?
显然我希望运行时的函数使用正确的asm,我知道我可以重新实现具有慢速函数的任何SIMD函数constexpr.
如果你想知道为什么我关心constexprSIMD功能.非constexprness具有传染性,这意味着我的任何使用SIMD功能的功能都不可能constexpr.
我正在尝试使用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()的等价物,这是一个关键因素.所以,我需要找到一种方法
模拟_mm_movemask_epi8() - 似乎很贵,有几个班次和OR
直接生成有效的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编程的开创性时代,将散射转换为收集是一种常见的技术,但这两种方法中没有一种看似实用.
也许如果不坚持压缩保留元素顺序将允许更有效的实现?我可以放弃.
我想为我和我的朋友写一个真正(非常)快速的Sobel算子用于射线追踪器(可以在这里找到源码).以下是我到目前为止所得到的......
首先,假设图像是8位无符号整数数组中逐行的灰度图像存储.
要编写真正的Sobel滤波器,我需要为每个像素计算Gx和Gy.由于原点旁边有6个像素,因此计算出这些数字中的每一个.但SIMD指令允许我处理16或甚至32(AVX)像素.希望运算符的内核具有一些不错的属性,因此我可以通过以下方式计算Gy:
我会做同样的(但转置)计算Gx然后添加两张图片.
一些说明:
(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的第一步,然后翻转结果图片以计算第二步.
所以,这是我的问题:
我有以下问题:
在__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)指令适合实现这一点?
可以使用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原语手动编写优化库?
我想测试#pragma omp parallel for和#pragma omp simd一个简单的矩阵追加程序.当我单独使用它们时,我没有错误,看起来很好.但是,我想测试使用它们可以获得多少性能.如果我#pragma omp parallel for在外循环#pragma omp simd之前和内循环之前使用,我也没有错误.当我在外部循环之前使用它们时发生错误.我在运行时遇到错误而不是编译时间.ICC并GCC返回错误,但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) …
我得到了一个小写字符数组(最多 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)