次に、この行列乗算の例のスカラー参照コードを示します。データは列に格納されます。
void matmul_mat8_scalar(input_window_int16* matA,
input_window_int16* matB,
output_window_int16* matC){
for(int i=0; i<M; i++){//M=64
for(int j=0;j<L;j++){//L=2
int temp = 0 ;
for(int k=0; k<N; k++){//N=8
temp += window_read(matA)*window_readincr(matB);//B is circular buffer, size N*L
window_incr(matA,64); //Jump of 64 elements to access the next element of the same row
}
window_write(matC,(int16_t)(temp>>15)) ;
window_incr(matC,64); //Jump to the next column
}
window_incr(matA,1); //Jump of one element for moving to the next row.
window_incr(matC,1); //Jump to the next row
}
}
前の例で解析したように、mac16
組み込み関数を使用すると、列から 16 int16 を一度にロードできるので、16 レーンを同時に計算するのに最適です。1 つの列で 16 の出力データを計算するには、mac16
演算が 4 回必要です。ベクター a 内の同じデータは、2 つの出力列のデータを計算するために 2 回使用されます。このため、2 つのデータ列をロードして、2 つの mac16
を 2 つの出力列に累積するために使用できます。これら 2 つのロードと 2 つの MAC が 4 回繰り返されて、2 つの出力列になります。この方法を次の疑似コードに示します。
C_[0:15,0] = A_[0:15,0:1]*B_[0:1,0]
C_[0:15,1] = A_[0:15,0:1]*B_[0:1,1]
C_[0:15,0]+= A_[0:15,2:3]*B_[2:3,0]
C_[0:15,1]+= A_[0:15,2:3]*B_[2:3,1]
C_[0:15,0]+= A_[0:15,4:5]*B_[4:5,0]
C_[0:15,1]+= A_[0:15,4:5]*B_[4:5,1]
C_[0:15,0]+= A_[0:15,6:7]*B_[6:7,0]
C_[0:15,1]+= A_[0:15,6:7]*B_[6:7,1]
前のコードでは、* がそれぞれ MAC 演算を示します。C_[0:15,0]
および C_[0:15,1]
は、個別に累算される 2 つの出力列を示します。A_[0:15,0:1]
は列 0 と 1 を示し、各列には 16 個の要素があります。B_[0:1,0]
は、2 つの要素を持つ列 0 を示します。64 行の出力があるため、実際にベクター化されたコードにはループがあります。使用される mac16
組み込み関数には、次のインターフェイスがあります。
v16acc48 mac16 ( v16acc48 acc,
v64int16 xbuff,
int xstart,
unsigned int xoffsets,
unsigned int xoffsets_hi,
unsigned int xsquare,
v16int16 zbuff,
int zstart,
unsigned int zoffsets,
unsigned int zoffsets_hi,
int zstep
)
バッファーには、バッファー (ベクター レジスタ) へのインデックスを計算するためのパラメーター (start、offsets、square、step) が含まれます。これらのパラメーターを使用したレーン アドレス指定方法の詳細は、MAC 組み込み関数 を参照してください。
mac16
組み込み関数のプロトタイプは、前の行列ベクター乗算の例で紹介したプロトタイプとは異なることに注意してください。この場合、xbuff
は v64int16
で、2 セットのデータをインターリーブ方式で格納および使用できます。
MAC 組み込み関数を使用したコード記述方法については、次のセクションを参照してください。