假设我有一个数组:
uint8_t arr[256];
Run Code Online (Sandbox Code Playgroud)
和一个元素
__m128i x
Run Code Online (Sandbox Code Playgroud)
包含16个字节,
x_1, x_2, ... x_16
Run Code Online (Sandbox Code Playgroud)
我想有效地填补一个新__m128i元素
__m128i y
Run Code Online (Sandbox Code Playgroud)
使用arr取决于值的值x,以便:
y_1 = arr[x_1]
y_2 = arr[x_2]
.
.
.
y_16 = arr[x_16]
Run Code Online (Sandbox Code Playgroud)
实现此目的的命令实质上是从非连续的一组存储器位置加载寄存器.我有一种痛苦的模糊记忆,看过这样一个命令的文档,但现在找不到它.它存在吗?在此先感谢您的帮助.
我有兴趣使用x86-64与gcc的SSE向量指令,并且不想为此使用任何内联汇编.有没有办法在C中做到这一点?如果是这样,有人可以举个例子吗?
如何在C中简化以下代码(当然使用SIMD内在函数)?我无法理解SIMD内在函数,这会有很大帮助:
int sum_naive( int n, int *a )
{
int sum = 0;
for( int i = 0; i < n; i++ )
sum += a[i];
return sum;
}
Run Code Online (Sandbox Code Playgroud) 假设有必要计算打包浮点数据的倒数或倒数平方根.两者都可以轻松完成:
__m128 recip_float4_ieee(__m128 x) { return _mm_div_ps(_mm_set1_ps(1.0f), x); }
__m128 rsqrt_float4_ieee(__m128 x) { return _mm_div_ps(_mm_set1_ps(1.0f), _mm_sqrt_ps(x)); }
Run Code Online (Sandbox Code Playgroud)
这种方法效果很好但很慢:根据指南,它们在Sandy Bridge上进行了14次和28次循环(吞吐量).对应的AVX版本在Haswell上几乎占用相同的时间.
另一方面,可以使用以下版本:
__m128 recip_float4_half(__m128 x) { return _mm_rcp_ps(x); }
__m128 rsqrt_float4_half(__m128 x) { return _mm_rsqrt_ps(x); }
Run Code Online (Sandbox Code Playgroud)
它们只需要一到两个时间周期(吞吐量),从而大大提升了性能.但是,它们非常接近:它们产生的结果相对误差小于1.5*2 ^ -12.鉴于单精度浮点数的机器epsilon是2 ^?24,我们可以说这种近似具有大约一半的精度.
似乎可以添加Newton-Raphson迭代以产生具有单精度的结果(可能不像IEEE标准所要求的那样精确),参见GCC,ICC,LLVM上的讨论.理论上,相同的方法可用于双精度值,产生半精度或单精度或双精度.
我有兴趣为float和double数据类型以及所有(half,single,double)精度实现此方法的实现.处理特殊情况(除以零,sqrt(-1),inf/nan等)不是必需的.此外,我不清楚这些例程中的哪一个比普通的IEEE编译解决方案更快,哪个更慢.
以下是对答案的一些小限制,请:
欢迎任何性能评估,测量和讨论.
以下是具有一次NR迭代的单精度浮点数的版本:
__m128 recip_float4_single(__m128 x) {
__m128 res = _mm_rcp_ps(x);
__m128 muls …Run Code Online (Sandbox Code Playgroud) 由于某种原因,cilk_spawn不适用于x86内在函数.每当我尝试将两者组合在同一函数的主体中时,我都会收到错误.(注意cilk_for工作正常).如果我删除所有SIMD指令,它编译并运行正常.
#include <stdio.h>
#include <x86intrin.h>
#include <math.h>
#include <cilk/cilk.h>
int main()
{
int w = cilk_spawn sqrt(10);
__m128i x = _mm_set_epi64x(1, 1);
x = _mm_add_epi64(x, x);
cilk_sync;
printf("%d\n", w);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这是gcc输出:
gcc-4.9 -std=c99 -march=native -fcilkplus -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"main.d" -MT"main.d" -o "main.o" "../main.c"
In file included from /usr/lib/gcc/x86_64-linux-gnu/4.9/include/xmmintrin.h:1258:0,
from /usr/lib/gcc/x86_64-linux-gnu/4.9/include/x86intrin.h:31,
from ../main.c:2:
../main.c: In function ‘main’:
/usr/lib/gcc/x86_64-linux-gnu/4.9/include/emmintrin.h:581:1: error: inlining failed in call to always_inline ‘_mm_set_epi64x’: function not inlinable
_mm_set_epi64x (long long __q1, long long …Run Code Online (Sandbox Code Playgroud) AVX512CD指令系列包括:VPCONFLICT,VPLZCNT和VPBROADCASTM.
AVX-512冲突检测(AVX-512CD)中的指令旨在帮助有效地计算通常无法安全矢量化的循环中元素的无冲突子集.
有哪些例子表明这些指令在向量化循环中有用?如果答案将包括标量循环及其矢量化对应物将会有所帮助.
谢谢!
让我们假设我们有一个函数,每个函数乘以两个1000000双精度数组.在C/C++中,函数如下所示:
void mul_c(double* a, double* b)
{
for (int i = 0; i != 1000000; ++i)
{
a[i] = a[i] * b[i];
}
}
Run Code Online (Sandbox Code Playgroud)
编译器生成以下程序集-O2:
mul_c(double*, double*):
xor eax, eax
.L2:
movsd xmm0, QWORD PTR [rdi+rax]
mulsd xmm0, QWORD PTR [rsi+rax]
movsd QWORD PTR [rdi+rax], xmm0
add rax, 8
cmp rax, 8000000
jne .L2
rep ret
Run Code Online (Sandbox Code Playgroud)
从上面的程序集看来,编译器似乎使用了SIMD指令,但每次迭代只会增加一倍.所以我决定在内联汇编中编写相同的函数,在那里我充分利用xmm0寄存器并一次乘以两个双精度:
void mul_asm(double* a, double* b)
{
asm volatile
(
".intel_syntax noprefix \n\t"
"xor rax, rax \n\t"
"0: \n\t"
"movupd …Run Code Online (Sandbox Code Playgroud) 我应该计算__m128i寄存器的设置位数.特别是,我应该使用以下方法编写两个能够计算寄存器位数的函数.
是否有可以完全或部分执行上述操作的内在功能?
我有一个行的行数组(~20 cols x~1M行),我需要一次从两个__m256寄存器中提取两列.
...a0.........b0......
...a1.........b1......
// ...
...a7.........b7......
// end first __m256
Run Code Online (Sandbox Code Playgroud)
一个天真的方法是这样做
__m256i vindex = _mm256_setr_epi32(
0,
1 * stride,
2 * stride,
// ...
7 * stride);
__m256 colA = _mm256_i32gather_ps(baseAddrColA, vindex, sizeof(float));
__m256 colB = _mm256_i32gather_ps(baseAddrColB, vindex, sizeof(float));
Run Code Online (Sandbox Code Playgroud)
但是,我想知道我是否会通过a0, b0, a1, b1, a2, b2, a3, b3在一个中检索gather而a4, b4, ... a7, b7在另一个中获得更好的性能,因为它们在内存中更接近,然后对它们进行反交错.那是:
// __m256 lo = a0 b0 a1 b1 a2 b2 a3 b3 // load proximal elements
// __m256 hi …Run Code Online (Sandbox Code Playgroud)