假设我管理一个名为__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
答案 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
未初始化)会失败,但是在这种情况下,性能并不重要,因此很容易处理。