对于使用SIMD打包成两个值的累积(单个)值,管理清除代码循环的方法是什么?

时间:2019-01-10 09:55:57

标签: c++ loops simd sse2

假设我管理一个名为__m128d的{​​{1}}变量,其计算公式为

v_phase

这是基本代码:

index 0 : load prev phase
index 1 : phase += newValue
index 2 : phase += newValue
index 3 : phase += newValue
index 4 : phase += newValue
...

事实是:如果__m128d v_phase; // load prev cumulated mPhase to v_phase (as mPhase, mPhase + nextValue) for (int sampleIndex = 0; sampleIndex < blockSize; sampleIndex += 2, pValue += 2) { // function with phase // update pValue increment (its not linear) // phase increment: v_phase += newValue } // cleanup code if (blockSize % 2 == 0) { mPhase = v_phase.m128d_f64[0]; } 是偶数,则工作正常:它将在最后一个循环迭代中求和另外两个相位值,并取blockSize(即新增加的两个中的第一个)。

但是如果v_phase.m128d_f64[0]是奇数怎么办?我只需要上次迭代的blockSize 而又不增加两个相位值

我可以使用v_phase.m128d_f64[1],但这将在sampleIndex < blockSize - 1中移动逻辑// function with phase(我不太喜欢)。

我会避免在循环中放置if(branc预测;由于我正在使用SIMD,因此我正在优化代码,这会减慢速度)。

有什么提示吗?

这是一个更“完整”的示例:

// cleanup code

1 个答案:

答案 0 :(得分:2)

除了最后一个,您还可以从循环中输出上一个 v_phase。也就是说,在更新您的v_phase之前,请存储上一个:

__m128d prev_v_phase;
for (...) {
    ...
    prev_v_phase = v_phase;
    v_phase = _mm_add_pd(v_phase, v_phaseAcc1);
    v_phase = _mm_add_pd(v_phase, v_phaseAcc2);
}

// cleanup code
if (blockSize % 2 == 0) {
    mPhase = v_phase.m128d_f64[0];
}
else {
    mPhase = prev_v_phase.m128d_f64[1];
}

如果循环根本不执行任何迭代(这将prev_v_phase未初始化)会失败,但是在这种情况下,性能并不重要,因此很容易处理。