c++ - 优化 uint8 的最大递减量

标签 c++ sse micro-optimization

我发现我的程序大部分时间都花在与此类似的循环中:

uint8_t (&c) [17] = ...
for (int x = 0; x < 16; x++) {
    if (c[x + 1] < c[x] - 1) {
        c[x + 1] = c[x] - 1;
    }
}

它将字段值计算为当前值和前一个字段值减去 1 的最大值。

有什么办法可以加快速度吗?

c 是多次 SSE 操作的结果,因此它可能已经在 xmm 中。然而,任何其他类型的改进也是最受欢迎的。

最佳答案

可以通过注意结果是最多 16 个独立内核(每个内核的形式为 0 0 0 0 N N-1 N-2 N-3 N-3)来打破依赖性。

__m128i d = _mm_loadu_si128((__m128i*)&c);  // get 16 bytes
__m128i ramp = _mm_set_epi8(15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0);
static __m128i bcast[16]; // shuffles item at i to i+1, i+2, ... 15
// e.g. bcast[3] = _mm_set_epi8(3,3,3,3,3,3,3,3,3,3,3,3,3,0xff,0xff,0xff);

for (i = 0; i < 16; i++)
    __m128i tmp = _mm_shuffle_epi8(d, bcast[i]);
    tmp = _mm_subs_epu8(tmp, ramp);  // saturated subtraction
    ramp = _mm_srli_si128(ramp, 1);        // Shift the ramp
    d = _mm_max_epu8(d, tmp);
}

d = max(d, x[i]) 生成的依赖关系实际上与顺序无关(假定不需要增量评估 Ram_i),并且依赖关系链可以折叠到二叉树。

但是我们可以做得比 16 次迭代更好——分治技术将任务分为下半部分和上半部分,每个迭代需要 8 次迭代(并且可以并行执行)。然后需要合并的最后阶段,必须将上面的结果 d[8..15] 与 d[0..7] 的递减尾部合并。

关于c++ - 优化 uint8 的最大递减量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43572641/

相关文章:

assembly - 这个 x86 汇编指令的作用是什么(addsd xmm0, ds :__xmm@41f00000000000000000000000000000[edx*8])?

Javascript 作用域链

c++ - 高斯模糊的SSE优化

c++ - 两个 SSE2 打包 double 的最优无分支条件选择

java - 在双(或多)循环内部或外部声明/初始化变量

javascript - 在 JavaScript 中读取数组的 `length` 属性真的是一项昂贵的操作吗?

c++ - 我想创建一个函数来读取输入的每一行并生成其总和并使用 C++ 将其保存为 sum.txt

c++ - 为什么clang不能启用所有的 sanitizer ?

c++ - SendInput,为什么不模拟向上箭头键?

c++ - 内存屏障/栅栏的开销