0

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 の番号が付けられた命令を並行して実行することによって行われます。

  1. これを行うには、配列 c[8] をレジスタ q0 と q1 にロードし、配列 src[256] をレジスタ q2 と q3 にロードします。この後、VMLA、VADD、VPADD を使用して変数 sum の結果を取得します。
  2. 直面している問題は、配列src の要素を(src[0]、src[4]、src[8] などとして) ロードする方法です。なぜなら、配列をロードする唯一の方法は [%1] によるものだからです。 ! 配列を順番にロードするだけです(src [0]、src [1]、src [2]など)。

また、命令 9 でポインター src を 2 ずつインクリメントするにはどうすればよいでしょうか?

4

1 に答える 1

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 (または、存在する場合は累積形式) を使用して内積を計算し、最後に水平方向に合計することができます。係数ベクトルを計算する方法を考え出す必要がありますが、それらはすべてゼロ以外の要素を 1 つしか持たないため、vset_lane を使用するだけです。

または、さらに良いことに、各係数ベクトルにはゼロ以外のエントリが 1 つしか含まれていないという事実を利用して、4 つの代わりに 1 つの multipyl を実行し、vdup_lane を使用して各レーンを抽出し、合計に追加できます。係数ベクトルを生成する必要があります

(c0  0  0  0)
(c1  0 c0 c1)
(c2 c0 c1 c2)
...
(c7 c5 c6 c7)

係数がすでに連続して保存されている場合、これは簡単なはずです。最初の要素を修正するだけです。

于 2012-08-07T18:45:07.693 に答える