当 NEON 向量指令在 ARM 设备上可用时,我一直在寻找复制各种数据量的快速方法。
\n我做了一些基准测试,并得到了一些有趣的结果。我试图理解我所看到的东西。
\n我有四个版本来复制数据:
\n逐个元素复制:
\nfor (int i = 0; i < size; ++i)\n{\n copy[i] = orig[i];\n}\nRun Code Online (Sandbox Code Playgroud)\n此代码将四个值加载到临时寄存器中,然后将该寄存器复制到输出。
\n因此,负载数量减少了一半。可能有一种方法可以跳过临时寄存器并将负载减少四分之一,但我还没有找到方法。
\nint32x4_t tmp;\nfor (int i = 0; i < size; i += 4)\n{\n tmp = vld1q_s32(orig + i); // load 4 elements to tmp SIMD register\n vst1q_s32(©2[i], tmp); // copy 4 elements from tmp SIMD register\n}\nRun Code Online (Sandbox Code Playgroud)\nmemcpy,使用memcpy,但一次复制 4 …
我想要一个类似 的函数的实现_mm256_lzcnt_epi8(__m256i a),其中对于每个 8 位元素,都会计算和提取尾随零的数量。
在上一个实现对前导零进行计数的问题中,有一个使用查找表的解决方案。我想知道是否可以使用相同的方法来实现这一点。
请仅使用 AVX 和 AVX2,并且输入的行为0可以是未定义的。
AVX2:AVX 寄存器中 8 位元素上的 BitScanReverse 或 CountLeadingZeros
感谢您的帮助!
我正在学习 SIMD 内在函数和并行计算。我不确定Intel对x86指令的定义sqrtpd是否 表示将同时计算传递给它的两个数字的平方根:
对源操作数(第二个操作数)中的两个、四个或八个压缩双精度浮点值的平方根执行 SIMD 计算,并将压缩双精度浮点结果存储在目标操作数(第二个操作数)中第一个操作数)。
我知道它明确表示SIMD 计算,但这是否意味着对于此操作,将同时计算两个数字的根?
我有一个三重嵌套循环,我想并行化,但是,我遇到了数据争用问题。我很确定我需要以某种方式使用缩减,但我不太知道如何使用。
这是有问题的循环:
#pragma omp parallel for simd collapse(3)
for (uint64 u = 0; u < nu; ++u) {
for (uint64 e = 0; e < ne; ++e) {
for (uint64 v = 0; v < nv; ++v) {
uAT[u][e] += _uT[u][e][v] * wA[e][v];
}
}
}
Run Code Online (Sandbox Code Playgroud)
有人可以向我解释一下,为什么这会导致数据竞争?我真的很想了解这一点,这样我将来就不会遇到这些问题。另外,这个循环可以并行吗?如果是这样,怎么办?
编辑:我怎么知道存在数据竞争?
这个循环应该完成的任务(并且它是串行完成的)是计算不连续伽辽金框架中函数的元素平均值。当我多次运行代码时,有时会得到不同的结果,尽管它应该总是产生相同的结果。产生的错误值总是小于应有的值,这就是为什么我假设某些值没有被添加。也许这张图可以更好地解释它:第三个单元格中的平均值显然是错误的(太小)。

我对编译器 intrinsincs 很陌生。我有 4 个 uint64_t 整数存储在 _m256i 中。
__m256i vj = _mm256_setr_epi64x(1, 2, 3, 4);
__m256i one = _mm256_set_epi64x(1, 1, 1, 1);
__m256i vf = _mm256_and_si256(vj, one); // vf = {1, 0, 1, 0}
Run Code Online (Sandbox Code Playgroud)
我想得到一个__m256d res = {1.0, -1.0, 1.0, -1.0}基于 vf 的值,如下所示:
double value[2] = {-1.0, 1.0};
for(int i = 0; i < 4; i++)
res[i] = value[vf[i]];
Run Code Online (Sandbox Code Playgroud)
从 vf 和 value 生成 res 的最佳方法应该是什么?非常感谢您的帮助。
所以我阅读了英特尔关于 _mm_blendv_ps 的文档,但不太明白该函数的真正作用。所以我写了下面的代码:
__m128 a = { 18.0,4.0,19.0,21.0 };
__m128 b = { 67.0,92.0,888.0,47.0 };
__m128 mask = { 1.0,0.0,0.0,1.0 };
__m128 result = _mm_blendv_ps(a, b, mask);
cout << "Result is: " << result[0] << " " << result[1] << " " << result[2] << " " << result[4] << endl;
Run Code Online (Sandbox Code Playgroud)
但我收到错误“没有运算符 [] 与这些操作数匹配”。为什么我无法访问结果?结果不是32位浮点向量吗?
那么为什么我无法访问结果呢?我怎样才能访问它?cout 的结果是什么(blendv 做什么)?
我有一个用例,其中我有位数组,每个位表示为8位整数,例如uint8_t data[] = {0,1,0,1,0,1,0,1};我想通过仅提取每个值的lsb来创建一个整数.我知道使用int _mm_movemask_pi8 (__m64 a)函数我可以创建一个掩码但这个内在函数只需要一个字节的msb而不是lsb.是否有类似的内在或有效方法来提取lsb以创建单个8位整数?
简单的C代码,只需添加一个双精度。
void test(double *a, double *b, long n) {
for (long j = 0; j < n; j++)
for (long i = 0; i < n; i++) {
b[i] = b[i] + a[j];
}
}
Run Code Online (Sandbox Code Playgroud)
在编译器资源管理器中获取ASM结果:https : //godbolt.org/z/tJ-d39
有一addpd和二addsd。两者都是与双精度有关的。
另一个类似的锈代码,获得了更多的双精度添加工具:https://godbolt.org/z/c49Wuh
pub unsafe fn test(a: &mut [f64], b: &mut [f64], n: usize) {
for j in 0..n {
for i in 0..n {
*b.get_unchecked_mut(i) = *b.get_unchecked_mut(i) + *a.get_unchecked_mut(j);
}
}
}
Run Code Online (Sandbox Code Playgroud) 我正在学习 C avx 内在函数,我想知道它是如何工作的。
我很熟悉我可以做这样的事情:
__m256 evens = _mm256_set_ps(2.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.0);
Run Code Online (Sandbox Code Playgroud)
这里我存储 8 个 32 位浮点数。所以这是 256 位。
但是假设我正在编写一个线性代数库。然后我如何处理任意数量的向量;例如,如何将 10 个 32 位浮点数放入 avx 向量中?
如果您能提供一些例子,我将非常感激
我的问题是ARM cortex-a8上的NEON单元有多少功能单元?如果我已经正确读取,TRM没有明确说明ARM cortex-a8的NEON核心上的功能单元数量.