我需要在Neon中实现以下循环。
int jump=4,c[8],i; //c[8] may be declared here
int *src,sum=0; //**EDIT:** src points to a 256 element array
for (i = 0; i < 4; i++)
{
sum = src[ i + 0 * jump] * c[0];//1
sum += src[ i + 1 * jump] * c[1];//2
sum += src[ i + 2 * jump] * c[2];//3
sum += src[ i + 3 * jump] * c[3];//4
sum += src[ i + 4 * jump] * c[4];//5
sum += src[ i + 5 * jump] * c[5];//6
sum += src[ i + 6 * jump] * c[6];//7
sum += src[ i + 7 * jump] * c[7];//8
src += 2; //9
}
**EDIT:**
The code can be shortened as-
int jump=4,c[8],i,j; //initialize array c
int *src,sum,a[256];//initialize array a
src=a;
for (i = 0; i < 4; i++)
{
sum=0;
for (j = 0; j < 8; j++)
{
int *p=src+ i + (j * jump);
sum += (*p)* c[j]; //sum += src[ i + j* jump] * c[j]
}
printf("Sum:%d\n",sum);
src += 2;
}
Just need to know a way to implement something like [%0]=[%0]+4 rather than [%0]!
主要优化将使用NEON中的 VMLA 指令并行运行编号为1-8的指令。
同样指令src如何在指令9中递增2 ?
答案 0 :(得分:1)
不是一个接一个地计算总和,而是同时计算它们。然后,您不需要跳过源值,因为每个源值(可能)会影响某些总和。基本上,你所做的就是计算(*表示点积)。
sum0 = source * (c0 0 0 0 c1 0 0 0 c2 0 0 0 ... c7 0 0 0 )
sum1 = source * ( 0 0 0 c0 0 0 0 c1 0 0 0 c2 ... 0 0 0 c7 )
sum2 = source * ( 0 0 0 0 0 0 c0 0 0 0 c1 0 ... 0 0 c6 0 )
sum3 = source * ( 0 0 0 0 0 0 0 0 0 c0 0 0 ... 0 c5 0 0 )
你可以通过
来做到这一点sum0 = sum1 = sum2 = sum3 = 0
sum0 += (s0 s1 s2 s3) * (c0 0 0 0)
sum1 += (s0 s1 s2 s3) * ( 0 0 0 c0)
sum2 += (s0 s1 s2 s3) * ( 0 0 0 0)
sum3 += (s0 s1 s2 s3) * ( 0 0 0 0)
sum0 += (s0 s1 s2 s3) * (c1 0 0 0)
sum1 += (s0 s1 s2 s3) * ( 0 0 0 c1)
sum2 += (s0 s1 s2 s3) * ( 0 0 c0 0)
sum3 += (s0 s1 s2 s3) * ( 0 0 0 0)
...
sum0 += (s0 s1 s2 s3) * (c7 0 0 0)
sum1 += (s0 s1 s2 s3) * ( 0 0 0 c7)
sum2 += (s0 s1 s2 s3) * ( 0 0 c6 0)
sum3 += (s0 s1 s2 s3) * ( 0 c5 0 0)
在各个步骤中,您实际上并不需要水平求和,您可以使用vmul.32(或者可能是它的累积形式,如果有的话)来计算点积,然后最后将它们水平相加。您只需要找出计算系数向量的方法,但由于它们都只有一个非零元素,因此您只需使用vset_lane。
或者,更好的是,您可以利用每个系数向量仅包含一个非零条目,并且执行一个多次而不是四次的事实,然后使用vdup_lane提取每个通道并将其添加到总和中。您需要生成系数向量
(c0 0 0 0)
(c1 0 c0 c1)
(c2 c0 c1 c2)
...
(c7 c5 c6 c7)
如果系数已经连续存储,这应该很容易 - 你只需要修复第一个元素。