让我先说一下..我对ASM的经验非常有限,对SIMD的经验更少。
但碰巧我有下面的MMX/SSE优化代码,我想将其移植到AltiVec指令中,以便在PPC/Cell处理器上使用。
这可能是一个很大的问题..尽管只有几行代码,我还是费了很大的劲才弄清楚这里到底发生了什么。
原功能:
static inline int convolve(const short *a, const short *b, int n)
{
int out = 0;
union {
__m64 m64;
int i32[2];
} tmp;
tmp.i32[0] = 0;
tmp.i32[1] = 0;
while (n >= 4) {
tmp.m64 = _mm_add_pi32(tmp.m64,
_mm_madd_pi16(*((__m64 *)a),
*((__m64 *)b)));
a += 4;
b += 4;
n -= 4;
}
out = tmp.i32[0] + tmp.i32[1];
_mm_empty();
while (n --)
out += (*(a++)) * (*(b++));
return out;
}
关于如何重写以使用AltiVec指令,有什么提示吗?
我的第一次尝试(一个非常错误的尝试)看起来像这样..但它不完全(甚至远程)正确。
static inline int convolve_altivec(const short *a, const short *b, int n)
{
int out = 0;
union {
vector unsigned int m128;
int i64[2];
} tmp;
vector unsigned int zero = {0, 0, 0, 0};
tmp.i64[0] = 0;
tmp.i64[1] = 0;
while (n >= 8) {
tmp.m128 = vec_add(tmp.m128,
vec_msum(*((vector unsigned short *)a),
*((vector unsigned short *)b), zero));
a += 8;
b += 8;
n -= 8;
}
out = tmp.i64[0] + tmp.i64[1];
#endif
while (n --)
out += (*(a++)) * (*(b++));
return out;
}
2条答案
按热度按时间h22fl7wq1#
你离得不远了--我修复了一些小问题,稍微清理了一下代码,添加了一个测试工具,现在看起来工作正常:
wnvonmuf2#
(警告:我所有的Altivec经验都来自Xbox360/PS3 -我不确定它们与其他Altivec平台有何不同)。
首先,你应该检查你的指针是否对齐。大多数向量加载(和存储)操作都应该来自16字节对齐的地址。如果不是,事情通常会在没有警告的情况下继续进行,但是你不会得到你所期望的数据。
也可以执行非对齐加载(但速度较慢),但基本上必须在数据前后读取一些数据,然后将它们组合起来。请参阅Apple's Altivec page。我在使用
lvlx
和lvrx
加载指令之前也做过这种操作,然后将它们进行“或”运算。接下来,我不确定你的乘法和加法是否相同。我从未使用过_mm_madd_pi16或vec_msum,所以我不确定它们是否等价。你应该在调试器中单步调试,并确保它们对相同的输入数据给予相同的输出。另一个可能的区别是它们可能以不同的方式处理溢出(例如,模运算与饱和运算)。
最后但并非最不重要的一点是,你一次计算4个int,而不是2个。所以你的并集应该包含4个int,最后你应该对所有4个int求和。