我是NEON的初学者,想要优化以下代码,但是当它编译并产生所需的相同输出时,我看不到任何改进。 AFAIK NEON有助于对连续的数据块进行操作,所以我希望在执行时间和周期方面有所改进。我做错了什么?
我正在使用-bu级优化的Ubuntu 12.04上的gcc
正常的c实现
git push origin master
霓虹灯表格
for(i= 0;i<9215;i++)
{
Z[i] = (L[i]>0)?0:1;
}
答案 0 :(得分:3)
问题:
void isNonNatural(int32_t * pDst, int32_t *pSrc, int n)
{
int32x4_t vec;
const int32x4_t one = vdupq_n_s32(1);
int32_t a;
unsigned int i;
if (n >= 4)
{
n -= 4;
while (1) {
do {
n -= 4;
vec = vld1q_s32(pSrc++);
vec = vqsubq_s32(vec, one);
vec = (int32x4_t) vshrq_n_u32((uint32x4_t) vec, 31);
vst1q_s32(pDst++, vec);
} while (n >= 0);
if (n <= -4) return;
// dealing with residuals
pSrc += n; // rewind pointers
pDst += n;
} // iterate for one last time
}
for (i = 0; i < n; ++i) {
a = *pSrc++;
if (a > 0) a = 0; else a = 1;
*pDst++ = a;
}
}
上面的这个函数应该比你的实现快一些。
vshrq_n_s32
代替。但它不会更快。编程NEON就像驾驶一辆大卡车一样。你不应该像小型车那样驾驶它。
虽然NEON可以同时计算多个数据,主要是在一个周期内,但它具有更高的指令延迟,通常为3~4个周期。换句话说,每个指令都必须等待前一个指令才能在上面的实现中返回结果。
实际上,避免这种情况的唯一方法是展开,这是一个很深的。
void isNonNatural_unroll(int32_t * pDst, int32_t *pSrc, int n)
{
int32x4_t vec1, vec2, vec3, vec4;
const int32x4_t one = vdupq_n_s32(1);
int32_t a;
unsigned int i;
if (n >= 16)
{
n -= 16;
while (1) {
do {
n -= 16;
vec1 = vld1q_s32(pSrc++);
vec2 = vld1q_s32(pSrc++);
vec3 = vld1q_s32(pSrc++);
vec4 = vld1q_s32(pSrc++);
vec1 = vqsubq_s32(vec1, one);
vec2 = vqsubq_s32(vec2, one);
vec3 = vqsubq_s32(vec3, one);
vec4 = vqsubq_s32(vec4, one);
vec1 = (int32x4_t) vshrq_n_u32((uint32x4_t) vec1, 31);
vec2 = (int32x4_t) vshrq_n_u32((uint32x4_t) vec2, 31);
vec3 = (int32x4_t) vshrq_n_u32((uint32x4_t) vec3, 31);
vec4 = (int32x4_t) vshrq_n_u32((uint32x4_t) vec4, 31);
vst1q_s32(pDst++, vec1);
vst1q_s32(pDst++, vec2);
vst1q_s32(pDst++, vec3);
vst1q_s32(pDst++, vec4);
} while (n >= 0);
if (n <= -16) return;
// dealing with residuals
pSrc += n; // rewind pointers
pDst += n;
} // iterate for one last time
}
if (n & 8)
{
vec1 = vld1q_s32(pSrc++);
vec2 = vld1q_s32(pSrc++);
vec1 = vqsubq_s32(vec1, one);
vec2 = vqsubq_s32(vec2, one);
vec1 = (int32x4_t) vshrq_n_u32((uint32x4_t) vec1, 31);
vec2 = (int32x4_t) vshrq_n_u32((uint32x4_t) vec2, 31);
vst1q_s32(pDst++, vec1);
vst1q_s32(pDst++, vec2);
}
if (n & 4)
{
vec1 = vld1q_s32(pSrc++);
vec1 = vqsubq_s32(vec1, one);
vec1 = (int32x4_t) vshrq_n_u32((uint32x4_t) vec1, 31);
vst1q_s32(pDst++, vec1);
}
n &= 3;
for (i = 0; i < n; ++i) {
a = *pSrc++;
if (a > 0) a = 0; else a = 1;
*pDst++ = a;
}
}
现在这个应该比以前的快得多,因为几乎所有的延迟都被隐藏(超过四倍的速度),只要可怜的编译器不会搞砸它。