SlideShare uma empresa Scribd logo
1 de 14
CPU GPU
Ultimate CGRA w/ high-speed compiler
CGRA for Energy-efficient Cryptography
Beyond-Neuromorphic Systems
Non-Deterministic Computing
1
ナレータ VOICEVOX:もち子(cv 明日葉よもぎ)
はらぺこエンジニアに贈るCGRAの世界2022
(8. 疎行列計算とソート編)
スパコンからIoTまで 省エネ社会に
AI+BCだけじゃない超効率計算手法
20220202
20220202
2
A*B ⇒ C
A*BT
⇒ C
A*BT
(疎行列) ⇒ C
A*BT
(圧縮表現) ⇒ C
疎行列の行列積
従来:CGRA演算は縦方向
20220202
3
IMAX:縦の圧縮は無意味なので横方向に演算
疎行列の行列積
20220202
4
疎行列積和
マージソート
1 1.0 2 2.0 3 3.0 11 4.0 12 5.0 13 6.0
配列A
配列B 2 1.0 3 2.0 4 3.0 9 4.0 10 5.0 11 6.0
要素番号と値の組
1 a1 2 a2 3 s3 11 a11 12 a12 13 a13
入力A
入力B 2 b2 3 b3 4 b4 9 b9 10 b10 11 b11
値と付加情報(ポインタなど)の組
疎行列とソートには、デュアルアドレス同調機能が便利
20220202
5
疎行列とソートには、デュアルアドレス同調機能が便利
4段パイプライン浮動小数点演算器+メモリ参照(LD+ST)
⑩+⑪+初回初期値C出力レジスタ⇒演算器入力REG
以降、累算 演算器3段結果⇒演算器入力REG
演算器入力REG⇒演算器初段結果⇒演算器2段結果
⇒演算器3段結果⇒演算器入力REGへ戻る累算リング
4段パイプラインAアドレス計算データフロー
①Aアドレス入力REG⇒②0/8加算出力⇒⑦通過
⇒⑨通過⇒先頭へ戻るアドレス累算リング
4段パイプラインBアドレス計算データフロー
①Bアドレス入力REG⇒②0/8加算出力⇒⑦通過
⇒⑨通過⇒先頭へ戻るアドレス累算リング
4段パイプラインAデータ参照フロー
⑤B組およびA組index比較+0/8加算出力
⇒⑥A先頭オフセット加算結果⇒⑧Aマスク結果
⇒④Aメモリ出力⇒先頭
4段パイプラインBデータ参照フロー
⑤B組およびA組index比較+0/8加算出力
⇒⑥B先頭オフセット加算結果⇒⑧Bマスク結果
⇒③Bメモリ出力⇒先頭
①
②
③ ④
⑤
⑥
⑦
⑧
⑨
⑩ ⑪
⑨
①
② ⑤
⑥
⑦
⑧
①
①
② ②
⑦ ⑦
⑨ ⑨
⑤
⑧
⑤
⑥ ⑥
⑧
④
③
⑩ ⑪
オフセット加算
アドレスマスク操作
読み出し結果 B42 読み出し結果 A00
B,A行列のベースアドレス
C02へのストア
20220202
6
4列多重化CGRAに5本のデータ流を埋め込む
mex(OP_CMPA_LE, &b0[h], INIT0?b:b0[h], INIT0?0:8, BR[r][2][1], BR[r][2][0]);
mex(OP_CMPA_GE, &a0[h][CHIP], INIT0?a[h][CHIP]:a0[h][CHIP], INIT0?0:8, BR[r][2][1], BR[r][2][0]);
mop(OP_LDR, 3, &BR[r][2][1], b0[h], bofs, MSK_W1, b, 2*LP*RMGRP, 0, 0, NULL, 2*LP*RMGRP);
mop(OP_LDR, 3, &BR[r][2][0], a0[h][CHIP], bofs, MSK_W0, a[h][CHIP], 2*LP, 0, 0, NULL, 2*LP);
mop(OP_LDWR, 1, &c00, c0[h][CHIP], oofs, MSK_W0, c[h][CHIP], RMGRP, 0, 1, NULL, RMGRP);
exe(OP_CFMA, &c00, INIT0?c00:c00, EXP_H3210, BR[r][2][1], EXP_H3210, BR[r][2][0], EXP_H3210, OP_NOP, 00);
mop(OP_STWR, 1, &c00, oofs, c0[h][CHIP], MSK_D0, c[h][CHIP], RMGRP, 0, 1, NULL, RMGRP);
20220202
7
4列多重化CGRAに5本のデータ流を埋め込む
mex(OP_CMPA_LE, &b0[h], INIT0?b:b0[h], INIT0?0:8, BR[r][2][1], BR[r][2][0]);
mex(OP_CMPA_GE, &a0[h][CHIP], INIT0?a[h][CHIP]:a0[h][CHIP], INIT0?0:8, BR[r][2][1], BR[r][2][0]);
mex(OP_CMPA_LE, &b0[h], INIT0?b:b0[h], INIT0?0:8, BR[r][2][1], BR[r][2][0]);
mex(OP_CMPA_GE, &a0[h][CHIP], INIT0?a[h][CHIP]:a0[h][CHIP], INIT0?0:8, BR[r][2][1], BR[r][2][0]);
mop(OP_LDR, 3, &BR[r][2][1], b0[h], bofs, MSK_W1, b, 2*LP*RMGRP, 0, 0, NULL, 2*LP*RMGRP);
mop(OP_LDR, 3, &BR[r][2][0], a0[h][CHIP], bofs, MSK_W0, a[h][CHIP], 2*LP, 0, 0, NULL, 2*LP);
mop(OP_LDR, 3, &BR[r][2][1], b0[h], bofs, MSK_W1, b, 2*LP*RMGRP, 0, 0, NULL, 2*LP*RMGRP);
mop(OP_LDR, 3, &BR[r][2][0], a0[h][CHIP], bofs, MSK_W0, a[h][CHIP], 2*LP, 0, 0, NULL, 2*LP);
mop(OP_LDWR, 1, &c00, c0[h][CHIP], oofs, MSK_W0, c[h][CHIP], RMGRP, 0, 1, NULL, RMGRP);
mop(OP_LDWR, 1, &c00, c0[h][CHIP], oofs, MSK_W0, c[h][CHIP], RMGRP, 0, 1, NULL, RMGRP);
exe(OP_CFMA, &c00, INIT0?c00:c00, EXP_H3210, BR[r][2][1], EXP_H3210, BR[r][2][0], EXP_H3210, OP_NOP, 00);
exe(OP_CFMA, &c00, INIT0?c00:c00, EXP_H3210, BR[r][2][1], EXP_H3210, BR[r][2][0], EXP_H3210, OP_NOP, 00);
mop(OP_STWR, 1, &c00, oofs, c0[h][CHIP], MSK_D0, c[h][CHIP], RMGRP, 0, 1, NULL, RMGRP);
mop(OP_STWR, 1, &c00, oofs, c0[h][CHIP], MSK_D0, c[h][CHIP], RMGRP, 0, 1, NULL, RMGRP);
20220202
8
4列多重化CGRAに10本のデータ流を埋め込む
20220202
9
void emax6sc_pth_imax_02(struct sc_param *param) {
Ull CHIP, LOOP0=param->LOOP0, LOOP1=param->LOOP1;
Ull INIT1[4], INIT0[4];
Uint uLOOP[4];
for (CHIP=0; CHIP<1; CHIP++) { /* unit2 */
uLOOP[CHIP]=LOOP1*LOOP0;
}
while (1) {
for (CHIP=0; CHIP<1; CHIP++)
if (uLOOP[CHIP]) break;
if (CHIP==1) break;
for (CHIP=0; CHIP<1; CHIP++) {
if (uLOOP[CHIP]==0) continue;
if ((2 && SCBR[1].enq[CHIP]==SCBR[1].deq[CHIP]) || (2<17 && SCBR[2].enq[CHIP]!=SCBR[2].deq[CHIP])) continue;
INIT1[CHIP]=(uLOOP[CHIP]>LOOP1*LOOP0-LOOP0);
INIT0[CHIP]=(uLOOP[CHIP]-(uLOOP[CHIP]/LOOP0*LOOP0)==0);
SCBR[1].deq[CHIP] = 1-SCBR[1].deq[CHIP];
{
SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][0] = SCBR[1].r[CHIP][SCBR[2].enq[CHIP]][6];
SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][3] = SCBR[1].r[CHIP][SCBR[2].enq[CHIP]][2];
}
{ Ull base, offs, adr, mexdist, load64;
static int emax6_unaligned_load_valid;
static Ull emax6_unaligned_load_high;
base = (!(0&1)||INIT0[CHIP]) ? ((0&2)?SCBR[1].r[CHIP][SCBR[2].enq[CHIP]][0]:SCM1[2].b[CHIP][0]) : SCM1[2].awoo[CHIP][0];
offs = eam(1 ? SCBR[1].r[CHIP][SCBR[2].enq[CHIP]][6] : SCM1[2].o[CHIP][0], 12);
mexdist = INIT0[CHIP] ? 0 : 0;
SCM1[2].awoo[CHIP][0] = (Ull)(INIT0[CHIP]?base:SCM1[2].awoo[CHIP][0]);
adr = (Uint)(SCM1[2].awoo[CHIP][0] + offs);
SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][1] = (Ull)*(Uint*)(adr&~3LL)<<32 | (Ull)*(Uint*)(adr&~3LL);
SCM1[2].d[CHIP][0] = SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][1];
}
{ Ull base, offs, adr, mexdist, load64;
static int emax6_unaligned_load_valid;
static Ull emax6_unaligned_load_high;
base = (!(1&1)||INIT0[CHIP]) ? ((1&2)?SCBR[1].r[CHIP][SCBR[2].enq[CHIP]][0]:SCM1[2].b[CHIP][2]) : SCM1[2].awoo[CHIP][2];
offs = eam(1 ? SCBR[1].r[CHIP][SCBR[2].enq[CHIP]][2] : SCM1[2].o[CHIP][2], 13);
mexdist = INIT0[CHIP] ? 0 : 8;
SCM1[2].awoo[CHIP][2] = (Ull)(INIT0[CHIP]?base:SCM1[2].awoo[CHIP][2])+(INIT0[CHIP]?0:((SCM0[2].d[CHIP][2]>>32)!=0xffffffff &&
(SCM1[2].d[CHIP][2]>>32)<=(SCM0[2].d[CHIP][2]>>32))?mexdist:0);
adr = (Uint)(SCM1[2].awoo[CHIP][2] + offs);
load64 = *(Ull*)(adr&~7LL);
if ((adr&7) == 0)
SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][9] = load64;
else if (!emax6_unaligned_load_valid) { /* BR[][][1] */
emax6_unaligned_load_valid = 1;
emax6_unaligned_load_high = load64;
SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][9] = load64 >> (adr&7)*8;
}
else { /* BR[][][0] */
emax6_unaligned_load_valid = 0;
SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][9] = emax6_unaligned_load_high << (8-(adr&7))*8 | load64 >> (adr&7)*8;
}
base = (!(1&1)||INIT0[CHIP]) ? ((1&2)?SCBR[1].r[CHIP][SCBR[2].enq[CHIP]][0]:SCM0[2].b[CHIP][2]) : SCM0[2].awoo[CHIP][2];
offs = eam(1 ? SCBR[1].r[CHIP][SCBR[2].enq[CHIP]][2] : SCM0[2].o[CHIP][2], 12);
mexdist = INIT0[CHIP] ? 0 : 8;
SCM0[2].awoo[CHIP][2] = (Ull)(INIT0[CHIP]?base:SCM0[2].awoo[CHIP][2])+(INIT0[CHIP]?0:((SCM1[2].d[CHIP][2]>>32)!=0xffffffff &&
(SCM1[2].d[CHIP][2]>>32)>=(SCM0[2].d[CHIP][2]>>32))?mexdist:0);
adr = (Uint)(SCM0[2].awoo[CHIP][2] + offs);
load64 = *(Ull*)(adr&~7LL);
if ((adr&7) == 0)
SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][8] = load64;
else if (!emax6_unaligned_load_valid) { /* BR[][][1] */
emax6_unaligned_load_valid = 1;
emax6_unaligned_load_high = load64;
SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][8] = load64 >> (adr&7)*8;
}
else { /* BR[][][0] */
emax6_unaligned_load_valid = 0;
SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][8] = emax6_unaligned_load_high << (8-(adr&7))*8 | load64 >> (adr&7)*8;
}
SCM1[2].d[CHIP][2] = SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][9];
SCM0[2].d[CHIP][2] = SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][8];
}
{ union { Uint i; float f; } f3, f2, f1, f0; Ull t3, t2, t1, t0, ex1, ex2, ex3, ex4, ex5, c1, c0, ex1_outd, ex2_outd;
ex1 = exm(!1||(INIT1[CHIP]&&INIT0[CHIP])||((1&1)&&INIT0[CHIP]) ? SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][1] : SCAR[2].r[CHIP][0], 0);
ex2 = exm(((1&2)&&!INIT0[CHIP]) ? 0 : SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][9], 0);
ex3 = exm(SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][8], 0);
f1.i = (Uint)(ex1);
f2.i = (Uint)(ex2>>32);
f3.i = (Uint)(ex3>>32);
if (f2.i != -1 && f2.i == f3.i) {
f2.i = (Uint)(ex2);
f3.i = (Uint)(ex3);
f0.f = f1.f + (f2.f * f3.f);
}
else {
f0.f = f1.f;
}
t0 = f0.i;
ex1_outd = t0;
ex2_outd = ex1_outd;
SCAR[2].r[CHIP][0] = ex2_outd;
}
{ Ull cs0, cs1, cs2, cs3, cex, base, offs, adr, mexdist;
cex = 3;
base = (!(2&1)||INIT0[CHIP]) ? ((2&2)?SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][0]:SCM0[2].b[CHIP][0]) : SCM0[2].awoo[CHIP][0];
offs = eam(0 ? SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][6] : SCM0[2].o[CHIP][0], 14);
mexdist = INIT0[CHIP] ? 0 : 0;
SCM0[2].awoo[CHIP][0] = (Ull)(INIT0[CHIP]?base:SCM0[2].awoo[CHIP][0]);
adr = (Uint)(SCM0[2].awoo[CHIP][0] + offs);
if (cex &1) *(Uint*)(adr&~3LL) = (1==1? SCAR[2].r[CHIP][0] : SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][6]);
}
uLOOP[CHIP]--;
SCBR[2].enq[CHIP] = 1-SCBR[2].enq[CHIP];
}
}
}
上のIMAXコードは4サイクルで全体を実行
逆コンパイルしC言語に戻すと以下の複雑さ
多機能を無理なくデータパスに収容してこそCGRAは高効率
mex(OP_CMPA_LE, &b0[h], INIT0?b:b0[h], INIT0?0:8, BR[r][2][1], BR[r][2][0]);
mex(OP_CMPA_GE, &a0[h][CHIP], INIT0?a[h][CHIP]:a0[h][CHIP], INIT0?0:8, BR[r][2][1], BR[r][2][0]);
mop(OP_LDR, 3, &BR[r][2][1], b0[h], bofs, MSK_W1, b, 2*LP*RMGRP, 0, 0, NULL, 2*LP*RMGRP);
mop(OP_LDR, 3, &BR[r][2][0], a0[h][CHIP], bofs, MSK_W0, a[h][CHIP], 2*LP, 0, 0, NULL, 2*LP);
mop(OP_LDWR, 1, &c00, c0[h][CHIP], oofs, MSK_W0, c[h][CHIP], RMGRP, 0, 1, NULL, RMGRP);
exe(OP_CFMA, &c00, INIT0?c00:c00, EXP_H3210, BR[r][2][1], EXP_H3210, BR[r][2][0], EXP_H3210, OP_NOP, 00);
mop(OP_STWR, 1, &c00, oofs, c0[h][CHIP], MSK_D0, c[h][CHIP], RMGRP, 0, 1, NULL, RMGRP);
IMAXコードと逆コンパイル結果の比較
①
①
② ②
⑦ ⑦
⑨ ⑨
⑤
⑧
⑤
⑥ ⑥
⑧
④
③
⑩ ⑪
オフセット加算
アドレスマスク操作
読み出し結果 B42 読み出し結果 A00
疎行列と同様、読み出し結果の大小関係に従い、
1次元配列内の異なるアドレスA,Bの片側を更新
後続ユニットにアドレスA,Bと、2つの読み出し
データを送り、アドレスとデータの各々の大小関
係に従い、いずれかのデータをストアすることに
より、LogN段のソートのうち、1段分を実現
ソート全体のLogN段のうち、1段分の
ソート結果をローカルメモリにストア
ストア先アドレスは単調増加
同時に後続ユニットが、前回の実行結果を前段の
ローカルメモリから読み出し、LogN段の次段以降
を担当する。全体として、ローカルメモリをダブル
バッファとするパイプライン実行が可能となる。
マージソートの作り方
20220202
10
マージソートの作り方
#define sort_core0(r, rp1, x, MASK_M, In, BE8) ¥
exe(OP_NOP, &AR[r][1], 0LL, EXP_H3210, 0LL, EXP_H3210, 0LL, EXP_H3210, OP_NOP, 0LL, OP_NOP, 0LL); /* stage#1 dmy */¥
exe(OP_ADD, &i, L8, EXP_H3210, 0LL, EXP_H3210, 0LL, EXP_H3210, OP_AND, MASK_M, OP_NOP, 0LL); /* stage#1 i = L8&M */¥
exe(OP_NOP, &AR[rp1][3], 0LL, EXP_H3210, 0LL, EXP_H3210, 0LL, EXP_H3210, OP_NOP, 0LL, OP_NOP, 0LL); /* stage#2 dmy */¥
exe(OP_ADD, &base, In, EXP_H3210, i, EXP_H3210, 0LL, EXP_H3210, OP_NOP, 0LL, OP_NOP, 0LL) /* stage#2 baseJ = &In[i], baseK = &In[i+BE] */
#define sort_core1(r, rp1, x, In, Ilen, BE8, Buf, Out, Olen) ¥
mex(OP_CMPA_LE, &J[x], INIT0?0LL:J[x], INIT0?0LL:8LL, OP_CMPA_GE, &K[x], INIT0?BE8:K[x], INIT0?0LL:8LL, BE8, BR[r][3][1], BR[r][3][0]); /* stage#3 */¥
mop(OP_LDR, 3, &BR[r][3][1], J[x], base, MSK_D0, In, Ilen, 0, 0, NULL, Ilen);/*LMM[2]確定 LD実行はcol2*//* stage#3 */¥
mop(OP_LDR, 3, &BR[r][3][0], K[x], base, MSK_D0, In, Ilen, 0, 0, NULL, Ilen);/*LMM[1]間借り LD実行はcol2*//* stage#3 */¥
exe(OP_CMP_LT, &cc0, J[x], EXP_H1010, BE8, EXP_H1010, 0LL, EXP_H3210, OP_NOP, 0LL, OP_NOP, 0);/* J[x]<BE8 */ /* stage#4 */¥
exe(OP_CMP_LT, &cc1, K[x], EXP_H1010, BE8*2, EXP_H1010, 0LL, EXP_H3210, OP_NOP, 0LL, OP_NOP, 0);/* K[x]<BE8 */ /* stage#4 */¥
exe(OP_CMP_LT, &cc2, BR[r][3][1], EXP_H3232, BR[r][3][0], EXP_H3232, 0LL, EXP_H3210, OP_NOP, 0LL, OP_NOP, 0);/* *J<*K */ /* stage#4 */¥
cex(OP_CEXE, &ex0, 0, cc2, cc1, cc0, 0x00a2); /* if (( cc2 && cc1 && cc0) || (!cc1 && cc0)) 7,5,1 0x00a2 *//* stage#5 */¥
mop(OP_STR, ex0, &BR[r][3][1], Buf, L8, MSK_W0, Out, Olen, 0, 0, NULL, Olen);/*LMM[1]間借り LD実行はcol2*//* stage#5 */¥
cex(OP_CEXE, &ex1, 0, cc2, cc1, cc0, 0x004c); /* if ((!cc2 && cc1 && cc0) || ( cc1 && !cc0)) 6,3,2 0x004c *//* stage#5 */¥
mop(OP_STR, ex1, &BR[r][3][0], Buf, L8, MSK_W0, Out, Olen, 0, 0, NULL, Olen) /*LMM[1]間借り LD実行はcol2*//* stage#5 */
for (Pipeline=0; Pipeline<NumBits; Pipeline++) {
for (Lmmrotate=0; Lmmrotate<NumBits*2; Lmmrotate++)
Buf[Lmmrotate] = &pseudoLMM[NumSamples*((Lmmrotate+NumBits*2-Pipeline)%(NumBits*2))];
//EMAX5A begin pipeline mapdist=0
for (CHIP=0; CHIP<NCHIP; CHIP++) {
for (INIT0=1,LOOP0=NumSamples,L8=0LL<<32|(0-8LL)&0xffffffff; LOOP0--; INIT0=0) { /* NumSamples<=4096 */
exe(OP_ADD, &L8, L8, EXP_H3210, 0LL<<32|8LL, EXP_H3210, 0LL, EXP_H3210, OP_NOP, 0LL, OP_NOP, 0LL); /* stage#0 */
#if (H==256)
sort_core0( 1, 2, 0, 0xfffffffffffffff0LL, In, 8LL); /* stage#1-2 */
sort_core1( 3, 4, 0, In, NumSamples2, 8LL, Buf[0], Buf[1], 0LL); /* stage#3-5 */
sort_core0( 3, 4, 1, 0xffffffffffffffe0LL, Buf[1], 16LL); /* stage#3-4 */
sort_core1( 5, 6, 1, Buf[1], 0LL, 16LL, Buf[2], Buf[3], 0LL); /* stage#5-7 */
sort_core0( 5, 6, 2, 0xffffffffffffffc0LL, Buf[3], 32LL); /* stage#5-6 */
sort_core1( 7, 8, 2, Buf[3], 0LL, 32LL, Buf[4], Buf[5], 0LL); /* stage#7-9 */
sort_core0( 7, 8, 3, 0xffffffffffffff80LL, Buf[5], 64LL); /* stage#7-8 */
sort_core1( 9, 10, 3, Buf[5], 0LL, 64LL, Buf[6], Buf[7], 0LL); /* stage#9-11 */
sort_core0( 9, 10, 4, 0xffffffffffffff00LL, Buf[7], 128LL); /* stage#9-10 */
sort_core1(11, 12, 4, Buf[7], 0LL, 128LL, Buf[8], Buf[9], 0LL); /* stage#11-13 */
sort_core0(11, 12, 5, 0xfffffffffffffe00LL, Buf[9], 256LL); /* stage#11-12 */
sort_core1(13, 14, 5, Buf[9], 0LL, 256LL, Buf[10], Buf[11],0LL); /* stage#13-15 */
sort_core0(13, 14, 6, 0xfffffffffffffc00LL, Buf[11], 512LL); /* stage#13-14 */
sort_core1(15, 16, 6, Buf[11], 0LL, 512LL, Buf[12], Buf[13],0LL); /* stage#15-17 */
sort_core0(15, 16, 7, 0xfffffffffffff800LL, Buf[13], 1024LL); /* stage#15-16 */
sort_core1(17, 18, 7, Buf[13], 0LL, 1024LL, Out, Out, NumSamples2); /* stage#17-19 */
#endif
}
//EMAX5A end
}
//EMAX5A drain_dirty_lmm
}
20220202
11
疎行列と同様、
読み出し結果の
大小関係に従い、
1次元配列内の
異なるアドレス
A,Bの片側を更
新
後続ユニットにアドレスA,Bと、2つの読み出しデータを送り、アドレスとデータの各々の大小関
係に従い、いずれかのデータをストアすることにより、LogN段のソートのうち、1段分を実現
ストア先アドレスは単調増加
ソート全体のLogN段のうち、1段分のソート結果をローカルメモリにストア
アドレスA
アドレスB データB データA
疎行列と同様、
読み出し結果の
大小関係に従い、
1次元配列内の
異なるアドレス
A,Bの片側を更
新
同一物理メモリ上で、計算結果を次に渡す
マージソートのコンパイル結果
20220202
12
おまけ。疎行列圧縮
count0 = 0;
for (row=0; row<M1; row++) {
for (col=0; col<M2; col++) {
if (A32_0[row*M2+col] == 0)
continue;
if (count0 >= M1*M2)
continue;
A32_P[count0].d = A32_0[row*M2+col];
A32_P[count0].x = row*M2+col;
count0++;
}
}
*Bas1P = B32_P-1; /* end of B32_0 */
for (i=0; i<M1; i+=RMGRP) {
r1 = (Ull)(i*M2-1)<<32;
ibase0 = B32_0+i*M2;
itop0 = B32_0+i*M2;
itop1 = itop0+RMGRP*M2;
obase0 = *Bas1P; /* end of B32_0 */
otop1 = otop0;
otop0 = *Bas1P+8; /* top of B32_P */
//with-prefetch/post-drain
//EMAX5A begin imax mapdist=0
for (CHIP=0; CHIP<NCHIP; CHIP++) {
for (INIT1=1,LOOP1=RMGRP,rofs=0; LOOP1--; INIT1=0) {
for (INIT0=1,LOOP0=M2,cofs=0; LOOP0--; INIT0=0) {
mop(OP_LDWR, 1, &r0, ibase0++, 0, MSK_D0, itop0, M2*RMGRP, 0, 0, itop1, M2*RMGRP);
exe(OP_ADD, &r1, r1, EXP_H3210, 0x100000000LL, EXP_H3210, 0, EXP_H3210, OP_NOP, 0, OP_NOP, 0LL);
exe(OP_NOP, &std, r1, EXP_H3210, 0, EXP_H3210, 0, EXP_H3210, OP_OR, r0, OP_NOP, 0LL);
exe(OP_CMP_EQ, &cc0, r0, EXP_H1010, 0x00000000LL, EXP_H1010, 0, EXP_H3210, OP_NOP, 0, OP_NOP, 0LL);
exe(OP_CMP_EQ, &cc1, r0, EXP_H1010, 0x80000000LL, EXP_H1010, 0, EXP_H3210, OP_NOP, 0, OP_NOP, 0LL);
exe(OP_NOP, &cc2, cc0, EXP_H3210, 0, EXP_H3210, 0, EXP_H1010, OP_OR, cc1, OP_NOP, 0LL);
exe(OP_CMOV, &oofs, cc2, EXP_H3210, 0, EXP_H3210, 8, EXP_H3210, OP_NOP, 0, OP_NOP, 0LL);
exe(OP_ADD, &obase0, obase0, EXP_H3210, oofs, EXP_H3210, 0, EXP_H3210, OP_NOP, 0, OP_NOP, 0LL);
mop(OP_STR, 3, &obase0, Bas1P, 0, MSK_D0, Bas1P, 2, 0, 0, NULL, 2);
exe(OP_NOP, &AR[5][0], 0, EXP_H3210, 0, EXP_H3210, 0, EXP_H1010, OP_NOP, 0, OP_NOP, 0LL);
cex(OP_CEXE, &ex0, 0, 0, 0, cc2, 0x0001);
mop(OP_STR, ex0, &std, obase0, 0, MSK_D0, otop0, LP*2*RMGRP, 0, 0, otop1, LP*2*RMGRP);
}
}
}
//EMAX5A end
//EMAX5A drain_dirty_lmm
}
20220202
13
20220202
14
今回のおさらい

Mais conteúdo relacionado

Semelhante a PBL1-v1-008j.pptx

PBL1-v1-006j.pptx
PBL1-v1-006j.pptxPBL1-v1-006j.pptx
PBL1-v1-006j.pptxNAIST
 
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)Takeshi Yamamuro
 
1072: アプリケーション開発を加速するCUDAライブラリ
1072: アプリケーション開発を加速するCUDAライブラリ1072: アプリケーション開発を加速するCUDAライブラリ
1072: アプリケーション開発を加速するCUDAライブラリNVIDIA Japan
 
文献紹介:Deep Analysis of CNN-Based Spatio-Temporal Representations for Action Re...
文献紹介:Deep Analysis of CNN-Based Spatio-Temporal Representations for Action Re...文献紹介:Deep Analysis of CNN-Based Spatio-Temporal Representations for Action Re...
文献紹介:Deep Analysis of CNN-Based Spatio-Temporal Representations for Action Re...Toru Tamaki
 
M5Stack互換機を作った話
M5Stack互換機を作った話M5Stack互換機を作った話
M5Stack互換機を作った話Masawo Yamazaki
 
Halide による画像処理プログラミング入門
Halide による画像処理プログラミング入門Halide による画像処理プログラミング入門
Halide による画像処理プログラミング入門Fixstars Corporation
 
PBL1-v1-009j.pptx
PBL1-v1-009j.pptxPBL1-v1-009j.pptx
PBL1-v1-009j.pptxNAIST
 
Polyphony の行く末(2018/3/3)
Polyphony の行く末(2018/3/3)Polyphony の行く末(2018/3/3)
Polyphony の行く末(2018/3/3)ryos36
 
CMSI計算科学技術特論B(14) OpenACC・CUDAによるGPUコンピューティング
CMSI計算科学技術特論B(14) OpenACC・CUDAによるGPUコンピューティングCMSI計算科学技術特論B(14) OpenACC・CUDAによるGPUコンピューティング
CMSI計算科学技術特論B(14) OpenACC・CUDAによるGPUコンピューティングComputational Materials Science Initiative
 
PL/CUDA - GPU Accelerated In-Database Analytics
PL/CUDA - GPU Accelerated In-Database AnalyticsPL/CUDA - GPU Accelerated In-Database Analytics
PL/CUDA - GPU Accelerated In-Database AnalyticsKohei KaiGai
 
PBL1-v1-003j.pptx
PBL1-v1-003j.pptxPBL1-v1-003j.pptx
PBL1-v1-003j.pptxNAIST
 
[CEDEC2017] LINEゲームのセキュリティ診断手法
[CEDEC2017] LINEゲームのセキュリティ診断手法[CEDEC2017] LINEゲームのセキュリティ診断手法
[CEDEC2017] LINEゲームのセキュリティ診断手法LINE Corporation
 
200625material naruse
200625material naruse200625material naruse
200625material naruseRCCSRENKEI
 
GPU-FPGA 協調計算を記述するためのプログラミング環境に関する研究(HPC169 No.10)
GPU-FPGA 協調計算を記述するためのプログラミング環境に関する研究(HPC169 No.10)GPU-FPGA 協調計算を記述するためのプログラミング環境に関する研究(HPC169 No.10)
GPU-FPGA 協調計算を記述するためのプログラミング環境に関する研究(HPC169 No.10)Ryuuta Tsunashima
 
Introduction to OpenCL (Japanese, OpenCLの基礎)
Introduction to OpenCL (Japanese, OpenCLの基礎)Introduction to OpenCL (Japanese, OpenCLの基礎)
Introduction to OpenCL (Japanese, OpenCLの基礎)Takahiro Harada
 
コンピューティングとJava~なにわTECH道
コンピューティングとJava~なにわTECH道コンピューティングとJava~なにわTECH道
コンピューティングとJava~なにわTECH道なおき きしだ
 
PyOpenCLによるGPGPU入門 Tokyo.SciPy#4 編
PyOpenCLによるGPGPU入門 Tokyo.SciPy#4 編PyOpenCLによるGPGPU入門 Tokyo.SciPy#4 編
PyOpenCLによるGPGPU入門 Tokyo.SciPy#4 編Yosuke Onoue
 
x86x64 SSE4.2 POPCNT
x86x64 SSE4.2 POPCNTx86x64 SSE4.2 POPCNT
x86x64 SSE4.2 POPCNTtakesako
 
非静力学海洋モデルkinacoのGPUによる高速化
非静力学海洋モデルkinacoのGPUによる高速化非静力学海洋モデルkinacoのGPUによる高速化
非静力学海洋モデルkinacoのGPUによる高速化Takateru Yamagishi
 

Semelhante a PBL1-v1-008j.pptx (20)

PBL1-v1-006j.pptx
PBL1-v1-006j.pptxPBL1-v1-006j.pptx
PBL1-v1-006j.pptx
 
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
 
1072: アプリケーション開発を加速するCUDAライブラリ
1072: アプリケーション開発を加速するCUDAライブラリ1072: アプリケーション開発を加速するCUDAライブラリ
1072: アプリケーション開発を加速するCUDAライブラリ
 
文献紹介:Deep Analysis of CNN-Based Spatio-Temporal Representations for Action Re...
文献紹介:Deep Analysis of CNN-Based Spatio-Temporal Representations for Action Re...文献紹介:Deep Analysis of CNN-Based Spatio-Temporal Representations for Action Re...
文献紹介:Deep Analysis of CNN-Based Spatio-Temporal Representations for Action Re...
 
M5Stack互換機を作った話
M5Stack互換機を作った話M5Stack互換機を作った話
M5Stack互換機を作った話
 
Halide による画像処理プログラミング入門
Halide による画像処理プログラミング入門Halide による画像処理プログラミング入門
Halide による画像処理プログラミング入門
 
PBL1-v1-009j.pptx
PBL1-v1-009j.pptxPBL1-v1-009j.pptx
PBL1-v1-009j.pptx
 
Polyphony の行く末(2018/3/3)
Polyphony の行く末(2018/3/3)Polyphony の行く末(2018/3/3)
Polyphony の行く末(2018/3/3)
 
Prosym2012
Prosym2012Prosym2012
Prosym2012
 
CMSI計算科学技術特論B(14) OpenACC・CUDAによるGPUコンピューティング
CMSI計算科学技術特論B(14) OpenACC・CUDAによるGPUコンピューティングCMSI計算科学技術特論B(14) OpenACC・CUDAによるGPUコンピューティング
CMSI計算科学技術特論B(14) OpenACC・CUDAによるGPUコンピューティング
 
PL/CUDA - GPU Accelerated In-Database Analytics
PL/CUDA - GPU Accelerated In-Database AnalyticsPL/CUDA - GPU Accelerated In-Database Analytics
PL/CUDA - GPU Accelerated In-Database Analytics
 
PBL1-v1-003j.pptx
PBL1-v1-003j.pptxPBL1-v1-003j.pptx
PBL1-v1-003j.pptx
 
[CEDEC2017] LINEゲームのセキュリティ診断手法
[CEDEC2017] LINEゲームのセキュリティ診断手法[CEDEC2017] LINEゲームのセキュリティ診断手法
[CEDEC2017] LINEゲームのセキュリティ診断手法
 
200625material naruse
200625material naruse200625material naruse
200625material naruse
 
GPU-FPGA 協調計算を記述するためのプログラミング環境に関する研究(HPC169 No.10)
GPU-FPGA 協調計算を記述するためのプログラミング環境に関する研究(HPC169 No.10)GPU-FPGA 協調計算を記述するためのプログラミング環境に関する研究(HPC169 No.10)
GPU-FPGA 協調計算を記述するためのプログラミング環境に関する研究(HPC169 No.10)
 
Introduction to OpenCL (Japanese, OpenCLの基礎)
Introduction to OpenCL (Japanese, OpenCLの基礎)Introduction to OpenCL (Japanese, OpenCLの基礎)
Introduction to OpenCL (Japanese, OpenCLの基礎)
 
コンピューティングとJava~なにわTECH道
コンピューティングとJava~なにわTECH道コンピューティングとJava~なにわTECH道
コンピューティングとJava~なにわTECH道
 
PyOpenCLによるGPGPU入門 Tokyo.SciPy#4 編
PyOpenCLによるGPGPU入門 Tokyo.SciPy#4 編PyOpenCLによるGPGPU入門 Tokyo.SciPy#4 編
PyOpenCLによるGPGPU入門 Tokyo.SciPy#4 編
 
x86x64 SSE4.2 POPCNT
x86x64 SSE4.2 POPCNTx86x64 SSE4.2 POPCNT
x86x64 SSE4.2 POPCNT
 
非静力学海洋モデルkinacoのGPUによる高速化
非静力学海洋モデルkinacoのGPUによる高速化非静力学海洋モデルkinacoのGPUによる高速化
非静力学海洋モデルkinacoのGPUによる高速化
 

Mais de NAIST

PBL1-v1-200j.pptx
PBL1-v1-200j.pptxPBL1-v1-200j.pptx
PBL1-v1-200j.pptxNAIST
 
PBL1-v1-200e.pptx
PBL1-v1-200e.pptxPBL1-v1-200e.pptx
PBL1-v1-200e.pptxNAIST
 
PBL1-v1-100j.pptx
PBL1-v1-100j.pptxPBL1-v1-100j.pptx
PBL1-v1-100j.pptxNAIST
 
PBL1-v1-100e.pptx
PBL1-v1-100e.pptxPBL1-v1-100e.pptx
PBL1-v1-100e.pptxNAIST
 
PBL1-v1-014j.pptx
PBL1-v1-014j.pptxPBL1-v1-014j.pptx
PBL1-v1-014j.pptxNAIST
 
PBL1-v1-014e.pptx
PBL1-v1-014e.pptxPBL1-v1-014e.pptx
PBL1-v1-014e.pptxNAIST
 
PBL1-v1-013j.pptx
PBL1-v1-013j.pptxPBL1-v1-013j.pptx
PBL1-v1-013j.pptxNAIST
 
PBL1-v1-013e.pptx
PBL1-v1-013e.pptxPBL1-v1-013e.pptx
PBL1-v1-013e.pptxNAIST
 
PBL1-v1-012j.pptx
PBL1-v1-012j.pptxPBL1-v1-012j.pptx
PBL1-v1-012j.pptxNAIST
 
PBL1-v1-012e.pptx
PBL1-v1-012e.pptxPBL1-v1-012e.pptx
PBL1-v1-012e.pptxNAIST
 
PBL1-v1-005j.pptx
PBL1-v1-005j.pptxPBL1-v1-005j.pptx
PBL1-v1-005j.pptxNAIST
 
PBL1-v1-004j.pptx
PBL1-v1-004j.pptxPBL1-v1-004j.pptx
PBL1-v1-004j.pptxNAIST
 
PBL1-v1-002j.pptx
PBL1-v1-002j.pptxPBL1-v1-002j.pptx
PBL1-v1-002j.pptxNAIST
 
PBL1-v1-001j.pptx
PBL1-v1-001j.pptxPBL1-v1-001j.pptx
PBL1-v1-001j.pptxNAIST
 
PBL1-v0-200j.pptx
PBL1-v0-200j.pptxPBL1-v0-200j.pptx
PBL1-v0-200j.pptxNAIST
 

Mais de NAIST (15)

PBL1-v1-200j.pptx
PBL1-v1-200j.pptxPBL1-v1-200j.pptx
PBL1-v1-200j.pptx
 
PBL1-v1-200e.pptx
PBL1-v1-200e.pptxPBL1-v1-200e.pptx
PBL1-v1-200e.pptx
 
PBL1-v1-100j.pptx
PBL1-v1-100j.pptxPBL1-v1-100j.pptx
PBL1-v1-100j.pptx
 
PBL1-v1-100e.pptx
PBL1-v1-100e.pptxPBL1-v1-100e.pptx
PBL1-v1-100e.pptx
 
PBL1-v1-014j.pptx
PBL1-v1-014j.pptxPBL1-v1-014j.pptx
PBL1-v1-014j.pptx
 
PBL1-v1-014e.pptx
PBL1-v1-014e.pptxPBL1-v1-014e.pptx
PBL1-v1-014e.pptx
 
PBL1-v1-013j.pptx
PBL1-v1-013j.pptxPBL1-v1-013j.pptx
PBL1-v1-013j.pptx
 
PBL1-v1-013e.pptx
PBL1-v1-013e.pptxPBL1-v1-013e.pptx
PBL1-v1-013e.pptx
 
PBL1-v1-012j.pptx
PBL1-v1-012j.pptxPBL1-v1-012j.pptx
PBL1-v1-012j.pptx
 
PBL1-v1-012e.pptx
PBL1-v1-012e.pptxPBL1-v1-012e.pptx
PBL1-v1-012e.pptx
 
PBL1-v1-005j.pptx
PBL1-v1-005j.pptxPBL1-v1-005j.pptx
PBL1-v1-005j.pptx
 
PBL1-v1-004j.pptx
PBL1-v1-004j.pptxPBL1-v1-004j.pptx
PBL1-v1-004j.pptx
 
PBL1-v1-002j.pptx
PBL1-v1-002j.pptxPBL1-v1-002j.pptx
PBL1-v1-002j.pptx
 
PBL1-v1-001j.pptx
PBL1-v1-001j.pptxPBL1-v1-001j.pptx
PBL1-v1-001j.pptx
 
PBL1-v0-200j.pptx
PBL1-v0-200j.pptxPBL1-v0-200j.pptx
PBL1-v0-200j.pptx
 

PBL1-v1-008j.pptx

  • 1. CPU GPU Ultimate CGRA w/ high-speed compiler CGRA for Energy-efficient Cryptography Beyond-Neuromorphic Systems Non-Deterministic Computing 1 ナレータ VOICEVOX:もち子(cv 明日葉よもぎ) はらぺこエンジニアに贈るCGRAの世界2022 (8. 疎行列計算とソート編) スパコンからIoTまで 省エネ社会に AI+BCだけじゃない超効率計算手法 20220202
  • 2. 20220202 2 A*B ⇒ C A*BT ⇒ C A*BT (疎行列) ⇒ C A*BT (圧縮表現) ⇒ C 疎行列の行列積
  • 4. 20220202 4 疎行列積和 マージソート 1 1.0 2 2.0 3 3.0 11 4.0 12 5.0 13 6.0 配列A 配列B 2 1.0 3 2.0 4 3.0 9 4.0 10 5.0 11 6.0 要素番号と値の組 1 a1 2 a2 3 s3 11 a11 12 a12 13 a13 入力A 入力B 2 b2 3 b3 4 b4 9 b9 10 b10 11 b11 値と付加情報(ポインタなど)の組 疎行列とソートには、デュアルアドレス同調機能が便利
  • 6. 4段パイプライン浮動小数点演算器+メモリ参照(LD+ST) ⑩+⑪+初回初期値C出力レジスタ⇒演算器入力REG 以降、累算 演算器3段結果⇒演算器入力REG 演算器入力REG⇒演算器初段結果⇒演算器2段結果 ⇒演算器3段結果⇒演算器入力REGへ戻る累算リング 4段パイプラインAアドレス計算データフロー ①Aアドレス入力REG⇒②0/8加算出力⇒⑦通過 ⇒⑨通過⇒先頭へ戻るアドレス累算リング 4段パイプラインBアドレス計算データフロー ①Bアドレス入力REG⇒②0/8加算出力⇒⑦通過 ⇒⑨通過⇒先頭へ戻るアドレス累算リング 4段パイプラインAデータ参照フロー ⑤B組およびA組index比較+0/8加算出力 ⇒⑥A先頭オフセット加算結果⇒⑧Aマスク結果 ⇒④Aメモリ出力⇒先頭 4段パイプラインBデータ参照フロー ⑤B組およびA組index比較+0/8加算出力 ⇒⑥B先頭オフセット加算結果⇒⑧Bマスク結果 ⇒③Bメモリ出力⇒先頭 ① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ ⑩ ⑪ ⑨ ① ② ⑤ ⑥ ⑦ ⑧ ① ① ② ② ⑦ ⑦ ⑨ ⑨ ⑤ ⑧ ⑤ ⑥ ⑥ ⑧ ④ ③ ⑩ ⑪ オフセット加算 アドレスマスク操作 読み出し結果 B42 読み出し結果 A00 B,A行列のベースアドレス C02へのストア 20220202 6 4列多重化CGRAに5本のデータ流を埋め込む
  • 7. mex(OP_CMPA_LE, &b0[h], INIT0?b:b0[h], INIT0?0:8, BR[r][2][1], BR[r][2][0]); mex(OP_CMPA_GE, &a0[h][CHIP], INIT0?a[h][CHIP]:a0[h][CHIP], INIT0?0:8, BR[r][2][1], BR[r][2][0]); mop(OP_LDR, 3, &BR[r][2][1], b0[h], bofs, MSK_W1, b, 2*LP*RMGRP, 0, 0, NULL, 2*LP*RMGRP); mop(OP_LDR, 3, &BR[r][2][0], a0[h][CHIP], bofs, MSK_W0, a[h][CHIP], 2*LP, 0, 0, NULL, 2*LP); mop(OP_LDWR, 1, &c00, c0[h][CHIP], oofs, MSK_W0, c[h][CHIP], RMGRP, 0, 1, NULL, RMGRP); exe(OP_CFMA, &c00, INIT0?c00:c00, EXP_H3210, BR[r][2][1], EXP_H3210, BR[r][2][0], EXP_H3210, OP_NOP, 00); mop(OP_STWR, 1, &c00, oofs, c0[h][CHIP], MSK_D0, c[h][CHIP], RMGRP, 0, 1, NULL, RMGRP); 20220202 7 4列多重化CGRAに5本のデータ流を埋め込む
  • 8. mex(OP_CMPA_LE, &b0[h], INIT0?b:b0[h], INIT0?0:8, BR[r][2][1], BR[r][2][0]); mex(OP_CMPA_GE, &a0[h][CHIP], INIT0?a[h][CHIP]:a0[h][CHIP], INIT0?0:8, BR[r][2][1], BR[r][2][0]); mex(OP_CMPA_LE, &b0[h], INIT0?b:b0[h], INIT0?0:8, BR[r][2][1], BR[r][2][0]); mex(OP_CMPA_GE, &a0[h][CHIP], INIT0?a[h][CHIP]:a0[h][CHIP], INIT0?0:8, BR[r][2][1], BR[r][2][0]); mop(OP_LDR, 3, &BR[r][2][1], b0[h], bofs, MSK_W1, b, 2*LP*RMGRP, 0, 0, NULL, 2*LP*RMGRP); mop(OP_LDR, 3, &BR[r][2][0], a0[h][CHIP], bofs, MSK_W0, a[h][CHIP], 2*LP, 0, 0, NULL, 2*LP); mop(OP_LDR, 3, &BR[r][2][1], b0[h], bofs, MSK_W1, b, 2*LP*RMGRP, 0, 0, NULL, 2*LP*RMGRP); mop(OP_LDR, 3, &BR[r][2][0], a0[h][CHIP], bofs, MSK_W0, a[h][CHIP], 2*LP, 0, 0, NULL, 2*LP); mop(OP_LDWR, 1, &c00, c0[h][CHIP], oofs, MSK_W0, c[h][CHIP], RMGRP, 0, 1, NULL, RMGRP); mop(OP_LDWR, 1, &c00, c0[h][CHIP], oofs, MSK_W0, c[h][CHIP], RMGRP, 0, 1, NULL, RMGRP); exe(OP_CFMA, &c00, INIT0?c00:c00, EXP_H3210, BR[r][2][1], EXP_H3210, BR[r][2][0], EXP_H3210, OP_NOP, 00); exe(OP_CFMA, &c00, INIT0?c00:c00, EXP_H3210, BR[r][2][1], EXP_H3210, BR[r][2][0], EXP_H3210, OP_NOP, 00); mop(OP_STWR, 1, &c00, oofs, c0[h][CHIP], MSK_D0, c[h][CHIP], RMGRP, 0, 1, NULL, RMGRP); mop(OP_STWR, 1, &c00, oofs, c0[h][CHIP], MSK_D0, c[h][CHIP], RMGRP, 0, 1, NULL, RMGRP); 20220202 8 4列多重化CGRAに10本のデータ流を埋め込む
  • 9. 20220202 9 void emax6sc_pth_imax_02(struct sc_param *param) { Ull CHIP, LOOP0=param->LOOP0, LOOP1=param->LOOP1; Ull INIT1[4], INIT0[4]; Uint uLOOP[4]; for (CHIP=0; CHIP<1; CHIP++) { /* unit2 */ uLOOP[CHIP]=LOOP1*LOOP0; } while (1) { for (CHIP=0; CHIP<1; CHIP++) if (uLOOP[CHIP]) break; if (CHIP==1) break; for (CHIP=0; CHIP<1; CHIP++) { if (uLOOP[CHIP]==0) continue; if ((2 && SCBR[1].enq[CHIP]==SCBR[1].deq[CHIP]) || (2<17 && SCBR[2].enq[CHIP]!=SCBR[2].deq[CHIP])) continue; INIT1[CHIP]=(uLOOP[CHIP]>LOOP1*LOOP0-LOOP0); INIT0[CHIP]=(uLOOP[CHIP]-(uLOOP[CHIP]/LOOP0*LOOP0)==0); SCBR[1].deq[CHIP] = 1-SCBR[1].deq[CHIP]; { SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][0] = SCBR[1].r[CHIP][SCBR[2].enq[CHIP]][6]; SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][3] = SCBR[1].r[CHIP][SCBR[2].enq[CHIP]][2]; } { Ull base, offs, adr, mexdist, load64; static int emax6_unaligned_load_valid; static Ull emax6_unaligned_load_high; base = (!(0&1)||INIT0[CHIP]) ? ((0&2)?SCBR[1].r[CHIP][SCBR[2].enq[CHIP]][0]:SCM1[2].b[CHIP][0]) : SCM1[2].awoo[CHIP][0]; offs = eam(1 ? SCBR[1].r[CHIP][SCBR[2].enq[CHIP]][6] : SCM1[2].o[CHIP][0], 12); mexdist = INIT0[CHIP] ? 0 : 0; SCM1[2].awoo[CHIP][0] = (Ull)(INIT0[CHIP]?base:SCM1[2].awoo[CHIP][0]); adr = (Uint)(SCM1[2].awoo[CHIP][0] + offs); SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][1] = (Ull)*(Uint*)(adr&~3LL)<<32 | (Ull)*(Uint*)(adr&~3LL); SCM1[2].d[CHIP][0] = SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][1]; } { Ull base, offs, adr, mexdist, load64; static int emax6_unaligned_load_valid; static Ull emax6_unaligned_load_high; base = (!(1&1)||INIT0[CHIP]) ? ((1&2)?SCBR[1].r[CHIP][SCBR[2].enq[CHIP]][0]:SCM1[2].b[CHIP][2]) : SCM1[2].awoo[CHIP][2]; offs = eam(1 ? SCBR[1].r[CHIP][SCBR[2].enq[CHIP]][2] : SCM1[2].o[CHIP][2], 13); mexdist = INIT0[CHIP] ? 0 : 8; SCM1[2].awoo[CHIP][2] = (Ull)(INIT0[CHIP]?base:SCM1[2].awoo[CHIP][2])+(INIT0[CHIP]?0:((SCM0[2].d[CHIP][2]>>32)!=0xffffffff && (SCM1[2].d[CHIP][2]>>32)<=(SCM0[2].d[CHIP][2]>>32))?mexdist:0); adr = (Uint)(SCM1[2].awoo[CHIP][2] + offs); load64 = *(Ull*)(adr&~7LL); if ((adr&7) == 0) SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][9] = load64; else if (!emax6_unaligned_load_valid) { /* BR[][][1] */ emax6_unaligned_load_valid = 1; emax6_unaligned_load_high = load64; SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][9] = load64 >> (adr&7)*8; } else { /* BR[][][0] */ emax6_unaligned_load_valid = 0; SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][9] = emax6_unaligned_load_high << (8-(adr&7))*8 | load64 >> (adr&7)*8; } base = (!(1&1)||INIT0[CHIP]) ? ((1&2)?SCBR[1].r[CHIP][SCBR[2].enq[CHIP]][0]:SCM0[2].b[CHIP][2]) : SCM0[2].awoo[CHIP][2]; offs = eam(1 ? SCBR[1].r[CHIP][SCBR[2].enq[CHIP]][2] : SCM0[2].o[CHIP][2], 12); mexdist = INIT0[CHIP] ? 0 : 8; SCM0[2].awoo[CHIP][2] = (Ull)(INIT0[CHIP]?base:SCM0[2].awoo[CHIP][2])+(INIT0[CHIP]?0:((SCM1[2].d[CHIP][2]>>32)!=0xffffffff && (SCM1[2].d[CHIP][2]>>32)>=(SCM0[2].d[CHIP][2]>>32))?mexdist:0); adr = (Uint)(SCM0[2].awoo[CHIP][2] + offs); load64 = *(Ull*)(adr&~7LL); if ((adr&7) == 0) SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][8] = load64; else if (!emax6_unaligned_load_valid) { /* BR[][][1] */ emax6_unaligned_load_valid = 1; emax6_unaligned_load_high = load64; SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][8] = load64 >> (adr&7)*8; } else { /* BR[][][0] */ emax6_unaligned_load_valid = 0; SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][8] = emax6_unaligned_load_high << (8-(adr&7))*8 | load64 >> (adr&7)*8; } SCM1[2].d[CHIP][2] = SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][9]; SCM0[2].d[CHIP][2] = SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][8]; } { union { Uint i; float f; } f3, f2, f1, f0; Ull t3, t2, t1, t0, ex1, ex2, ex3, ex4, ex5, c1, c0, ex1_outd, ex2_outd; ex1 = exm(!1||(INIT1[CHIP]&&INIT0[CHIP])||((1&1)&&INIT0[CHIP]) ? SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][1] : SCAR[2].r[CHIP][0], 0); ex2 = exm(((1&2)&&!INIT0[CHIP]) ? 0 : SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][9], 0); ex3 = exm(SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][8], 0); f1.i = (Uint)(ex1); f2.i = (Uint)(ex2>>32); f3.i = (Uint)(ex3>>32); if (f2.i != -1 && f2.i == f3.i) { f2.i = (Uint)(ex2); f3.i = (Uint)(ex3); f0.f = f1.f + (f2.f * f3.f); } else { f0.f = f1.f; } t0 = f0.i; ex1_outd = t0; ex2_outd = ex1_outd; SCAR[2].r[CHIP][0] = ex2_outd; } { Ull cs0, cs1, cs2, cs3, cex, base, offs, adr, mexdist; cex = 3; base = (!(2&1)||INIT0[CHIP]) ? ((2&2)?SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][0]:SCM0[2].b[CHIP][0]) : SCM0[2].awoo[CHIP][0]; offs = eam(0 ? SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][6] : SCM0[2].o[CHIP][0], 14); mexdist = INIT0[CHIP] ? 0 : 0; SCM0[2].awoo[CHIP][0] = (Ull)(INIT0[CHIP]?base:SCM0[2].awoo[CHIP][0]); adr = (Uint)(SCM0[2].awoo[CHIP][0] + offs); if (cex &1) *(Uint*)(adr&~3LL) = (1==1? SCAR[2].r[CHIP][0] : SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][6]); } uLOOP[CHIP]--; SCBR[2].enq[CHIP] = 1-SCBR[2].enq[CHIP]; } } } 上のIMAXコードは4サイクルで全体を実行 逆コンパイルしC言語に戻すと以下の複雑さ 多機能を無理なくデータパスに収容してこそCGRAは高効率 mex(OP_CMPA_LE, &b0[h], INIT0?b:b0[h], INIT0?0:8, BR[r][2][1], BR[r][2][0]); mex(OP_CMPA_GE, &a0[h][CHIP], INIT0?a[h][CHIP]:a0[h][CHIP], INIT0?0:8, BR[r][2][1], BR[r][2][0]); mop(OP_LDR, 3, &BR[r][2][1], b0[h], bofs, MSK_W1, b, 2*LP*RMGRP, 0, 0, NULL, 2*LP*RMGRP); mop(OP_LDR, 3, &BR[r][2][0], a0[h][CHIP], bofs, MSK_W0, a[h][CHIP], 2*LP, 0, 0, NULL, 2*LP); mop(OP_LDWR, 1, &c00, c0[h][CHIP], oofs, MSK_W0, c[h][CHIP], RMGRP, 0, 1, NULL, RMGRP); exe(OP_CFMA, &c00, INIT0?c00:c00, EXP_H3210, BR[r][2][1], EXP_H3210, BR[r][2][0], EXP_H3210, OP_NOP, 00); mop(OP_STWR, 1, &c00, oofs, c0[h][CHIP], MSK_D0, c[h][CHIP], RMGRP, 0, 1, NULL, RMGRP); IMAXコードと逆コンパイル結果の比較
  • 10. ① ① ② ② ⑦ ⑦ ⑨ ⑨ ⑤ ⑧ ⑤ ⑥ ⑥ ⑧ ④ ③ ⑩ ⑪ オフセット加算 アドレスマスク操作 読み出し結果 B42 読み出し結果 A00 疎行列と同様、読み出し結果の大小関係に従い、 1次元配列内の異なるアドレスA,Bの片側を更新 後続ユニットにアドレスA,Bと、2つの読み出し データを送り、アドレスとデータの各々の大小関 係に従い、いずれかのデータをストアすることに より、LogN段のソートのうち、1段分を実現 ソート全体のLogN段のうち、1段分の ソート結果をローカルメモリにストア ストア先アドレスは単調増加 同時に後続ユニットが、前回の実行結果を前段の ローカルメモリから読み出し、LogN段の次段以降 を担当する。全体として、ローカルメモリをダブル バッファとするパイプライン実行が可能となる。 マージソートの作り方 20220202 10
  • 11. マージソートの作り方 #define sort_core0(r, rp1, x, MASK_M, In, BE8) ¥ exe(OP_NOP, &AR[r][1], 0LL, EXP_H3210, 0LL, EXP_H3210, 0LL, EXP_H3210, OP_NOP, 0LL, OP_NOP, 0LL); /* stage#1 dmy */¥ exe(OP_ADD, &i, L8, EXP_H3210, 0LL, EXP_H3210, 0LL, EXP_H3210, OP_AND, MASK_M, OP_NOP, 0LL); /* stage#1 i = L8&M */¥ exe(OP_NOP, &AR[rp1][3], 0LL, EXP_H3210, 0LL, EXP_H3210, 0LL, EXP_H3210, OP_NOP, 0LL, OP_NOP, 0LL); /* stage#2 dmy */¥ exe(OP_ADD, &base, In, EXP_H3210, i, EXP_H3210, 0LL, EXP_H3210, OP_NOP, 0LL, OP_NOP, 0LL) /* stage#2 baseJ = &In[i], baseK = &In[i+BE] */ #define sort_core1(r, rp1, x, In, Ilen, BE8, Buf, Out, Olen) ¥ mex(OP_CMPA_LE, &J[x], INIT0?0LL:J[x], INIT0?0LL:8LL, OP_CMPA_GE, &K[x], INIT0?BE8:K[x], INIT0?0LL:8LL, BE8, BR[r][3][1], BR[r][3][0]); /* stage#3 */¥ mop(OP_LDR, 3, &BR[r][3][1], J[x], base, MSK_D0, In, Ilen, 0, 0, NULL, Ilen);/*LMM[2]確定 LD実行はcol2*//* stage#3 */¥ mop(OP_LDR, 3, &BR[r][3][0], K[x], base, MSK_D0, In, Ilen, 0, 0, NULL, Ilen);/*LMM[1]間借り LD実行はcol2*//* stage#3 */¥ exe(OP_CMP_LT, &cc0, J[x], EXP_H1010, BE8, EXP_H1010, 0LL, EXP_H3210, OP_NOP, 0LL, OP_NOP, 0);/* J[x]<BE8 */ /* stage#4 */¥ exe(OP_CMP_LT, &cc1, K[x], EXP_H1010, BE8*2, EXP_H1010, 0LL, EXP_H3210, OP_NOP, 0LL, OP_NOP, 0);/* K[x]<BE8 */ /* stage#4 */¥ exe(OP_CMP_LT, &cc2, BR[r][3][1], EXP_H3232, BR[r][3][0], EXP_H3232, 0LL, EXP_H3210, OP_NOP, 0LL, OP_NOP, 0);/* *J<*K */ /* stage#4 */¥ cex(OP_CEXE, &ex0, 0, cc2, cc1, cc0, 0x00a2); /* if (( cc2 && cc1 && cc0) || (!cc1 && cc0)) 7,5,1 0x00a2 *//* stage#5 */¥ mop(OP_STR, ex0, &BR[r][3][1], Buf, L8, MSK_W0, Out, Olen, 0, 0, NULL, Olen);/*LMM[1]間借り LD実行はcol2*//* stage#5 */¥ cex(OP_CEXE, &ex1, 0, cc2, cc1, cc0, 0x004c); /* if ((!cc2 && cc1 && cc0) || ( cc1 && !cc0)) 6,3,2 0x004c *//* stage#5 */¥ mop(OP_STR, ex1, &BR[r][3][0], Buf, L8, MSK_W0, Out, Olen, 0, 0, NULL, Olen) /*LMM[1]間借り LD実行はcol2*//* stage#5 */ for (Pipeline=0; Pipeline<NumBits; Pipeline++) { for (Lmmrotate=0; Lmmrotate<NumBits*2; Lmmrotate++) Buf[Lmmrotate] = &pseudoLMM[NumSamples*((Lmmrotate+NumBits*2-Pipeline)%(NumBits*2))]; //EMAX5A begin pipeline mapdist=0 for (CHIP=0; CHIP<NCHIP; CHIP++) { for (INIT0=1,LOOP0=NumSamples,L8=0LL<<32|(0-8LL)&0xffffffff; LOOP0--; INIT0=0) { /* NumSamples<=4096 */ exe(OP_ADD, &L8, L8, EXP_H3210, 0LL<<32|8LL, EXP_H3210, 0LL, EXP_H3210, OP_NOP, 0LL, OP_NOP, 0LL); /* stage#0 */ #if (H==256) sort_core0( 1, 2, 0, 0xfffffffffffffff0LL, In, 8LL); /* stage#1-2 */ sort_core1( 3, 4, 0, In, NumSamples2, 8LL, Buf[0], Buf[1], 0LL); /* stage#3-5 */ sort_core0( 3, 4, 1, 0xffffffffffffffe0LL, Buf[1], 16LL); /* stage#3-4 */ sort_core1( 5, 6, 1, Buf[1], 0LL, 16LL, Buf[2], Buf[3], 0LL); /* stage#5-7 */ sort_core0( 5, 6, 2, 0xffffffffffffffc0LL, Buf[3], 32LL); /* stage#5-6 */ sort_core1( 7, 8, 2, Buf[3], 0LL, 32LL, Buf[4], Buf[5], 0LL); /* stage#7-9 */ sort_core0( 7, 8, 3, 0xffffffffffffff80LL, Buf[5], 64LL); /* stage#7-8 */ sort_core1( 9, 10, 3, Buf[5], 0LL, 64LL, Buf[6], Buf[7], 0LL); /* stage#9-11 */ sort_core0( 9, 10, 4, 0xffffffffffffff00LL, Buf[7], 128LL); /* stage#9-10 */ sort_core1(11, 12, 4, Buf[7], 0LL, 128LL, Buf[8], Buf[9], 0LL); /* stage#11-13 */ sort_core0(11, 12, 5, 0xfffffffffffffe00LL, Buf[9], 256LL); /* stage#11-12 */ sort_core1(13, 14, 5, Buf[9], 0LL, 256LL, Buf[10], Buf[11],0LL); /* stage#13-15 */ sort_core0(13, 14, 6, 0xfffffffffffffc00LL, Buf[11], 512LL); /* stage#13-14 */ sort_core1(15, 16, 6, Buf[11], 0LL, 512LL, Buf[12], Buf[13],0LL); /* stage#15-17 */ sort_core0(15, 16, 7, 0xfffffffffffff800LL, Buf[13], 1024LL); /* stage#15-16 */ sort_core1(17, 18, 7, Buf[13], 0LL, 1024LL, Out, Out, NumSamples2); /* stage#17-19 */ #endif } //EMAX5A end } //EMAX5A drain_dirty_lmm } 20220202 11
  • 12. 疎行列と同様、 読み出し結果の 大小関係に従い、 1次元配列内の 異なるアドレス A,Bの片側を更 新 後続ユニットにアドレスA,Bと、2つの読み出しデータを送り、アドレスとデータの各々の大小関 係に従い、いずれかのデータをストアすることにより、LogN段のソートのうち、1段分を実現 ストア先アドレスは単調増加 ソート全体のLogN段のうち、1段分のソート結果をローカルメモリにストア アドレスA アドレスB データB データA 疎行列と同様、 読み出し結果の 大小関係に従い、 1次元配列内の 異なるアドレス A,Bの片側を更 新 同一物理メモリ上で、計算結果を次に渡す マージソートのコンパイル結果 20220202 12
  • 13. おまけ。疎行列圧縮 count0 = 0; for (row=0; row<M1; row++) { for (col=0; col<M2; col++) { if (A32_0[row*M2+col] == 0) continue; if (count0 >= M1*M2) continue; A32_P[count0].d = A32_0[row*M2+col]; A32_P[count0].x = row*M2+col; count0++; } } *Bas1P = B32_P-1; /* end of B32_0 */ for (i=0; i<M1; i+=RMGRP) { r1 = (Ull)(i*M2-1)<<32; ibase0 = B32_0+i*M2; itop0 = B32_0+i*M2; itop1 = itop0+RMGRP*M2; obase0 = *Bas1P; /* end of B32_0 */ otop1 = otop0; otop0 = *Bas1P+8; /* top of B32_P */ //with-prefetch/post-drain //EMAX5A begin imax mapdist=0 for (CHIP=0; CHIP<NCHIP; CHIP++) { for (INIT1=1,LOOP1=RMGRP,rofs=0; LOOP1--; INIT1=0) { for (INIT0=1,LOOP0=M2,cofs=0; LOOP0--; INIT0=0) { mop(OP_LDWR, 1, &r0, ibase0++, 0, MSK_D0, itop0, M2*RMGRP, 0, 0, itop1, M2*RMGRP); exe(OP_ADD, &r1, r1, EXP_H3210, 0x100000000LL, EXP_H3210, 0, EXP_H3210, OP_NOP, 0, OP_NOP, 0LL); exe(OP_NOP, &std, r1, EXP_H3210, 0, EXP_H3210, 0, EXP_H3210, OP_OR, r0, OP_NOP, 0LL); exe(OP_CMP_EQ, &cc0, r0, EXP_H1010, 0x00000000LL, EXP_H1010, 0, EXP_H3210, OP_NOP, 0, OP_NOP, 0LL); exe(OP_CMP_EQ, &cc1, r0, EXP_H1010, 0x80000000LL, EXP_H1010, 0, EXP_H3210, OP_NOP, 0, OP_NOP, 0LL); exe(OP_NOP, &cc2, cc0, EXP_H3210, 0, EXP_H3210, 0, EXP_H1010, OP_OR, cc1, OP_NOP, 0LL); exe(OP_CMOV, &oofs, cc2, EXP_H3210, 0, EXP_H3210, 8, EXP_H3210, OP_NOP, 0, OP_NOP, 0LL); exe(OP_ADD, &obase0, obase0, EXP_H3210, oofs, EXP_H3210, 0, EXP_H3210, OP_NOP, 0, OP_NOP, 0LL); mop(OP_STR, 3, &obase0, Bas1P, 0, MSK_D0, Bas1P, 2, 0, 0, NULL, 2); exe(OP_NOP, &AR[5][0], 0, EXP_H3210, 0, EXP_H3210, 0, EXP_H1010, OP_NOP, 0, OP_NOP, 0LL); cex(OP_CEXE, &ex0, 0, 0, 0, cc2, 0x0001); mop(OP_STR, ex0, &std, obase0, 0, MSK_D0, otop0, LP*2*RMGRP, 0, 0, otop1, LP*2*RMGRP); } } } //EMAX5A end //EMAX5A drain_dirty_lmm } 20220202 13

Notas do Editor

  1. 様々なアプリケーションを取りあげて、アイマックスのポテンシャルを説明するシリーズです。第8回は、そ行列計算とソートです。
  2. 最近では、圧縮されたそ行列を扱うプログラムも増えてきました。対応できるCGRAしか生き残れません。
  3. アイマックスでは、みつ行列積は縦方向に、そ行列積は横方向にマッピングします。こんな感じで、自在に対応することができます。
  4. そ行列計算でも、マージソートでも、データを比較して、大小関係に基づいて、次に見るメモリアドレスを変更する機能が必要です。うえのそぎょうれつは、要素の左に要素番号、右にあたいが入っています。あたいがゼロの要素は、掛け算しても無駄なので、このようなあっしゅく形式を使って、メモリと計算時間を節約します。要素番号が同じもの同士をさがして、掛け算するためには、メモリからロードした要素番号を比較して、小さいほうを先に進める機能が必要です。下のマージソートでは、要素の左にあたい、右に付加情報がはいっています。この場合も、あたいを比較して、小さいほうを出力して、アドレスを先に進める機能が必要です。
  5. ふつうのCGRAには望むべくもない機能です。でも、アイマックスには、各ユニットの、デュアルポートローカルメモリに、そ行列にも、マージソートにも使える、デュアルアドレス同調機能がついています。これは、5個、または、10個のリングデータパスを、知恵の輪のように組み合わせて、最大性能を出す仕掛けです。もし、理解できたら、あなたも、すごいCGRAを開発できることでしょう。
  6. これは、5個のリングデータパスを組み合わせた、そ行列計算のデータフローです。一度に1要素を計算できる、簡単なほうです。
  7. 実際のコードは、上のように書きます。タイミングチャートは下の図です。タイミングチャートの横軸は時間を、縦軸はアイマックス内部のレジスタやメモリの名前をあらわしていて、同じ時間に2つ重なっていたら、それは実行できないコードです。時間軸上の波形は1クロックずつ仕切られていて、アイマックスは、この単位で動作します。コードの色と、チャート中の色が対応しています。これを見ると、矛盾なくアイマックスが動作すること、また、ハードウェアが休むことなく動作していることがわかります。でも、まだ隙間があります。
  8. ということで、プログラムを上のように書きなおすと、10個のリングデータパスに増えて、スループットが2倍になります。これで、ハードウェアがめいっぱい動作します。
  9. 参考までに、5個のリングデータパスを組み合わせた、上の7行のコードは、アイマックスでは、4サイクルでパイプライン実行します。60ユニットを使うと、さらに60倍の性能です。下は、同じプログラムをノイマン型コンピュータ向けに自動変換、つまり、逆コンパイルしたプログラムです。とても長いプログラムになりました。これは4サイクルでは到底実行できません。アイマックスは、多くの機能をコンパクトかつ巧妙にデータパスに埋め込んで、効率良く計算する仕組みであることがわかります。単に、CGRAにしたからできるというものではありません。例えるなら、ノイマン型コンピュータは都心の有名大型デパート、ふつうのCGRAはコンビニ、アイマックスは秋葉原高架下の超高密度電気街といったところです。
  10. 次は、マージソートです。そ行列の場合、1つのユニットで行列積計算を完結できました。マージソートの場合は、次のユニットと組み合わせて、ソート結果をストアします。そ行列のデータフローに、少し足すだけで、マージソートのできあがりです。
  11. プログラムは、こういう具合に書きます。今までの使い方と違って、中間の、ソート結果を書き込むローカルメモリは、外部メモリとのやりとりは行わず、ユニット間で、ダブルバッファの役割を果たします。赤字部分は、条件付きストアを使って、ソートしている部分です。3つのCMPと、3つの比較結果を巧妙に組み合わせて、コンパクトなコードにしています。どうしてこれで、マージソートができるのか、自分で、よく考えましょう。
  12. コンパイル結果です。2つのユニットで、N要素のマージソート1段分を実行します。ソート結果は、後続のユニットが受け取り、次のN要素のソートを実行します。つまり、計算量、オーダーNログNのマージソートを、ろぐN段のユニットでパイプライン実行していることになります。アイマックスのマージソートの計算速度は、オーダーNということですね。28ユニットを使うと4096要素、64ユニットを使うと、理論上は10億要素までソートできます。理論上といったのは、ローカルメモリも16ギガバイトあればということです。実際には、128KBくらいなので、今のプログラムのままでは、1万6千要素が限界です。
  13. おまけ。アイマックスは、0を含む密行列を、圧縮形式に変換することもできます。赤枠は、CPUのコード、左は、アイマックスのコードです。赤字部分の比較結果を使って、青字の条件付きストアを実行することで、行列を圧縮します。同時に、緑のストアは、圧縮後の要素数を出力します。
  14. 今回は、そ行列計算とマージソートを題材に、デュアルアドレス同調機能と、ローカルメモリのダブルバッファ機能を説明しました。では、今回はここまでです。おつかれさま。