让我用..开始吧。我使用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;
}发布于 2010-12-04 18:46:07
你离得不远了--我修复了一些小问题,清理了一些代码,添加了一个测试工具,现在似乎可以正常工作了:
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <altivec.h>
static int convolve_ref(const short *a, const short *b, int n)
{
int out = 0;
int i;
for (i = 0; i < n; ++i)
{
out += a[i] * b[i];
}
return out;
}
static inline int convolve_altivec(const short *a, const short *b, int n)
{
int out = 0;
union {
vector signed int m128;
int i32[4];
} tmp;
const vector signed int zero = {0, 0, 0, 0};
assert(((unsigned long)a & 15) == 0);
assert(((unsigned long)b & 15) == 0);
tmp.m128 = zero;
while (n >= 8)
{
tmp.m128 = vec_msum(*((vector signed short *)a),
*((vector signed short *)b), tmp.m128);
a += 8;
b += 8;
n -= 8;
}
out = tmp.i32[0] + tmp.i32[1] + tmp.i32[2] + tmp.i32[3];
while (n --)
out += (*(a++)) * (*(b++));
return out;
}
int main(void)
{
const int n = 100;
vector signed short _a[n / 8 + 1];
vector signed short _b[n / 8 + 1];
short *a = (short *)_a;
short *b = (short *)_b;
int sum_ref, sum_test;
int i;
for (i = 0; i < n; ++i)
{
a[i] = rand();
b[i] = rand();
}
sum_ref = convolve_ref(a, b, n);
sum_test = convolve_altivec(a, b, n);
printf("sum_ref = %d\n", sum_ref);
printf("sum_test = %d\n", sum_test);
printf("%s\n", sum_ref == sum_test ? "PASS" : "FAIL");
return 0;
}发布于 2010-12-04 18:01:49
(警告:我所有的Altivec体验都来自于在Xbox360/PS3上的工作-我不确定它们与其他Altivec平台有多大的不同)。
首先,你应该检查你的指针对齐方式。大多数向量加载(和存储)操作都应该来自16字节对齐的地址。如果它们不是,事情通常会在没有警告的情况下继续进行,但您不会获得预期的数据。
可以(但速度较慢)执行未对齐的加载,但基本上必须在数据之前和之后读取一些数据并将它们组合起来。参见Apple's Altivec page。在使用lvlx和lvrx加载指令之前,我也这样做过,然后将它们ORing在一起。
接下来,我不确定你的乘法和加法是否相同。我从来没有使用过_mm_madd_pi16或vec_msum,所以我不能肯定它们是等价的。您应该在调试器中单步执行,并确保它们为相同的输入数据提供相同的输出。另一个可能的差异是,它们可能会以不同的方式处理溢出(例如,模块化与饱和化)。
最后但并非最不重要的一点是,你一次要计算4个整型数而不是2个整型数,所以你的联盟应该有4个整型数,最后你应该把所有4个整型数加起来。
https://stackoverflow.com/questions/4351383
复制相似问题