【发布时间】:2014-07-19 20:06:31
【问题描述】:
我是第一次学习 SSE 并尝试优化一些代码。我有两个问题。
SSE 逻辑似乎有点不对劲。该代码用于重新采样音频,但它只会产生噪音,因此它在某处显然是错误的。
我认为没有我的帮助编译器会做得更好。
更新:我意识到 pos4 和 frac4 的初始值是错误的,我正在更新下面的代码。但是在其他地方仍然存在逻辑错误。
//我在SSE的尝试
typedef unsigned int ALuint;
typedef float ALfloat;
static __inline __m128 lerp_SSE( const __m128 mu, const __m128 val1, const __m128 val2 ) {
/* val1 + (val2-val1)*mu */
const __m128 r0 = _mm_sub_ps( val2, val1 );
const __m128 r1 = _mm_mul_ps( mu, r0 );
const __m128 r2 = _mm_add_ps( val1, r1 );
return r2;
}
void Resample_lerp32_SSE(const ALfloat *data, ALuint frac,
ALuint increment, ALfloat *RESTRICT OutBuffer, ALuint BufferSize)
{
ALuint i;
ALuint pos;
ALuint pos0_tmp = 0;
ALuint frac0_tmp = frac;
ALuint frac0_incr = frac0_tmp + increment;
ALuint pos1_tmp = frac0_incr>>FRACTIONBITS;
ALuint frac1_tmp = (frac0_incr & FRACTIONMASK);
ALuint frac1_incr = frac1_tmp + increment;
ALuint pos2_tmp = pos1_tmp + (frac1_incr>>FRACTIONBITS);
ALuint frac2_tmp = (frac1_incr & FRACTIONMASK);
ALuint frac2_incr = frac2_tmp + increment;
ALuint pos3_tmp = pos2_tmp + (frac2_incr>>FRACTIONBITS);
ALuint frac3_tmp = (frac2_incr & FRACTIONMASK);
__m128i frac4 = _mm_set_epi32(frac3_tmp, frac2_tmp, frac1_tmp, frac0_tmp);
const __m128i increment4 = _mm_set1_epi32(increment);
const __m128 fracOne4 = _mm_set1_ps(1.0f/FRACTIONONE);
const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK);
__m128i pos4 = _mm_set_epi32(pos3_tmp, pos2_tmp, pos1_tmp, pos0_tmp);
for(i = 0;i < BufferSize-3;i += 4)
{
__m128 val1 = _mm_set_ps(data[pos3_tmp], data[pos2_tmp], data[pos1_tmp], data[pos0_tmp]);
__m128 val2 = _mm_set_ps(data[pos3_tmp+1], data[pos2_tmp+1], data[pos1_tmp+1], data[pos0_tmp+1]);
__m128 mu = _mm_mul_ps(_mm_cvtepi32_ps(frac4), fracOne4);
__m128 out = lerp_SSE(mu, val1, val2);
_mm_store_ps(&OutBuffer[i], out);
frac4 = _mm_add_epi32(frac4, increment4);
pos4 = _mm_add_epi32(pos4, _mm_srli_epi32(frac4, FRACTIONBITS));
frac4 = _mm_and_si128(frac4, fracMask4);
pos0_tmp = _mm_extract_epi32(pos4, 0);
pos1_tmp = _mm_extract_epi32(pos4, 1);
pos2_tmp = _mm_extract_epi32(pos4, 2);
pos3_tmp = _mm_extract_epi32(pos4, 3);
}
pos = pos0_tmp;
for(;i < BufferSize;i++)
{
const ALfloat *vals = data + pos;
OutBuffer[i] = lerp(vals[0], vals[1], frac * (1.0f/FRACTIONONE));
frac += increment;
pos += frac>>FRACTIONBITS;
frac &= FRACTIONMASK;
}
}
//纯C版本
void Resample_lerp_C(const ALfloat *data, ALuint frac,
ALuint increment, ALfloat *RESTRICT OutBuffer, ALuint BufferSize)
{
ALuint pos = 0;
ALuint i;
for(i = 0;i < BufferSize+1;i++)
{
OutBuffer[i] = lerp32(data + pos, frac);
frac += increment;
pos += frac>>FRACTIONBITS;
frac &= FRACTIONMASK;
}
}
【问题讨论】:
-
这样的帖子适合codereview.stackexchange.com。
-
@RSahu: codereview.stackexchange.com 用于 working 代码 - OP 说他的代码无法正常工作(优化是次要问题,因为没有必要尝试优化损坏的代码)。
-
@PaulR 感谢您指出不同之处。我没有意识到这一点。
-
只是为了澄清非 SSE 代码工作正常。
-
问题解决了我忙于仔细检查我使用了正确的内在函数,我没有注意到我没有将值增加正确的数量 const __m128i increment4 = _mm_set1_epi32(increment);需要为: const __m128i increment4 = _mm_set1_epi32(increment*4);
标签: c optimization assembly x86 sse