SlideShare ist ein Scribd-Unternehmen logo
1 von 24
CPU GPU
Ultimate CGRA w/ high-speed compiler
CGRA for Energy-efficient Cryptography
Beyond-Neuromorphic Systems
Non-Deterministic Computing
1
ナレータ VOICEVOX:もち子(cv 明日葉よもぎ)
はらぺこエンジニアに贈るCGRAの世界2022
(10. 高速コンパイラ編)
20220819
2
Variety of local memory access
20220819
3
FMA C+B*A ⇒ D
Dual Random access
20220819
4
FMA C+B*A ⇒ D
C has location info (next unit)
D has location info (same as C)
Sequential updates
20220819
5
FMA C+B*A ⇒ D
D has location info (same as C)
Sequential updates
20220819
6
FMA C+B*A ⇒ C
Accumulation
20220202
7
命令テンプレート(自由記述は非効率、超CISC的表現が必要)
cex(OP_CEXE, &ex0-9, c3, c2, c1, c0, 16bit-pattern)
c3,c2,c2,c1は各々64bit値であり,bit32を連結した4bitと,bit0を連結した4bitにより,各々,16bit-patternのbit位置を
取り出した結果が,ex[0-9]のbit1およびbit0に格納される.ex0-9のbit1は条件付きストアの上位32bit,bit0は条件付きス
トアの下位32bitに対応する.
exe(OP_X, &var|&AR[0-63][0-3], s1, e1, s2, e2, s3, e3, OP_Y, s4, OP_Z, s5)
ex4(OP_X, &var|&AR[0-63], s1, e1, s2, e2, s3, e3, OP_Y, s4, OP_Z, s5)
varまたはAR[0-63][0-3]はALUの演算結果格納先であり,前者は位置情報無し,後者は行列位置情報に対応する.s1か
らs3の各64bit値は,各々,e1からe3による修飾後に演算器に入力される.修飾子は以下の通り.
EXP_H3210: 無加工
EXP_H1010: 下位32bitを上位+下位32bitにコピー
EXP_H3232: 上位32bitを上位+下位32bitにコピー
EXP_B5410: byte5,4,1,0を各々16bitに拡張し連結
EXP_B7632: byte7,6,3,2を各々16bitに拡張し連結
OP_Xには主に算術演算,OP_Yには主に論理演算,OP_Zには主にシフト演算を記述できる.各演算はSIMD型であり,上
位32bitと下位32bitを独立に扱う.exe()は倍幅、ex4()は8倍幅のSIMDである.
20220202
8
命令テンプレート
exe(OP_X, &var, INIT0?var:var, e1, s2, e2, s3, e3, OP_Y, s4, OP_Z, s5)
INIT0?var:varは,C言語としては常にvarであるため冗長である.これは,CGRAにおいてホストの介入無しに多重ループ
に対応する工夫である.多重ループ起動前に,ホストは,内側ループに関する各初期値をCGRA内にセットする.通常,
内側ループ完了時にホストが介入して内部レジスタの再初期化を行う必要がある.しかし,IMAXでは,INIT0?var:varが
記述された変数は,CGRAが自ら再初期化を行い,ホスト介入のオーバヘッドを排除している.具体的には,varに初期値
がセットされていることを前提に,LOOP0の初回(INIT0=1)は,ホストが予めセットした当該初期値を演算器の第1入力とし,
次回以降は演算器出力を第1入力とするようデータパスを切替える.
exe(OP_X, &var, var, e1, INIT0?s2:0, e2, s3, e3, OP_Y, s4, OP_Z, s5)
これも,CGRAにおいて,ホストの介入無しに多重ループに対応する工夫である.INIT0?s2:0が記述されている場合,
LOOP0の初回(INIT0=1)は,s2を演算器の第2入力とし,次回以降は0を第2入力とするようデータパスを切替える.2次元
サブアレイの先頭アドレス計算に利用できる.
20220202
9
命令テンプレート
mex(OP MEX2, &s2, INIT0?s20:s2, INIT0?0:expr, OP MEX1, &s1, INIT0?s10:s1,
INIT0?0:expr, limit, BR[0-63][0-3][1], BR[0-63][0-3][0])
ホストの介入無しに多重ループ疎行列計算またはマージソートを行うためのアドレス計算補助記述.INIT0?s20:s2 および
INIT0?s10:s1 はベースアドレス,INIT0?0:expr は加算するオフセットに対応する.LOOP0 の初回 (INIT0=1) は,s2 と s1に,
s20とs10(初期値)が格納され,次回以降は,前回ロー カルメモリから読み出した 2 つの64bitデータの上位32bitを比較し,
大小関係によって,s2またはs1,す なわちアドレス計算器出力に,0またはexprを加算した結果が格納される.また,limit
はマージソート用の比較対象間距離である.使用方法はプログラム例を参照のこと.OP_MEX は以下の通り.
OP_NOP: 常にbase
OP_ALWAYS: 常にbase+offset
OP_CMPA_LE: 上位32bit(BR[][][1])≦上位32bit(BR[][][0])ならbase+offset.それ以外はbase
OP_CMPA_GE: 上位32bit(BR[][][1])≧上位32bit(BR[][][0])ならbase+offset.それ以外はbase?_
20220202
10
命令テンプレート
mop(OP_X, ex9-0, &src|&dst, base, offset, mask, top, len, block, force, ptop, plen)
mo4(OP_X, ex9-0, &src|&dst, base, offset, mask, top, len, block, force, ptop, plen)
ローカルメモリに対するロードまたはストアを記述する.各項目は以下の通り.
OP_X: データ幅に応じた倍幅SIMD型ロード命令またはストア命令.mo4は8倍幅SIMDである
ex0-9: 無条件ストアの場合は定数3,前述の条件付きストアの場合は変数
src|dst: ロードの場合は格納先レジスタ,ストアの場合はストアデータ
base: 参照するメモリアドレス base+mask(offset) のbase部分.ホストの主記憶アドレスをそのまま使える.ローカルメモリ内アドレスへはコンパイラと
ハードウェアの連携により自動変換するので,アドレス変換を意識する必要はない
offset: 同じくoffset部分.offsetの単位は1byteである点に注意
mask: 最終的なアドレスは,baseに,offsetレジスタをmaskにより修飾した値を加えたもの.MSK_B0:bit7-0、MSK_B1:bit15-8、MSK_B2:bit23-16、
MSK_B3:bit31-24、MSK_B4:bit39-32、MSK_B5:bit47-40、MSK_B6:bit55-48、MSK_B7:bit63-56、MSK_H0:bit15-0、MSK_H1:bit31-16、
MSK_H2:bit47-32、MSK_H3:bit63-48、MSK_W0:bit31-0、MSK_W1:bit63-32、MSK_D0:bit63-0
top: バースト演算が参照するホスト主記憶の先頭アドレス.先頭アドレスと長さを用いてホストDMAコントローラがホスト主記憶-LMM間転送を行う
len: 同じく長さ.単位は1word(4byte)である.なお,DMA転送速度は256bit/cycleである.lenに定数0を指定した場合,topにより指定された領域が
確保されるものの,DMAは抑止される.この指定は,同一LMMによるダブルバッファリングを行う際に使用する.
block: IMAXでは使用しない(EMAX5ではDMAギャザ機能のパラメタ)
force: ロードとストアとで動作が異なる
0: ロードの場合,前回DMAの先頭アドレスおよび長さが同一であればDMAを起動せずLMMを再利用する.ストアの場合,バースト演算後に
LMMからホスト主記憶にデータ転送する.ただし,次回バースト演算と同時の遅延ドレインが指定されている場合はDMAを抑止する.
1: ロードの場合,必ずホスト主記憶からLMMにデータ転送する.外部機器入力のように,アドレスが同じでも内容が異なる場合に使用する.
ストアの場合,パーシャルストア(一部アドレスのみストア)を想定し,バースト演算前にホスト主記憶から一旦LMMにデータ転送する.ただし,
前回ストアとアドレス範囲が同じ場合はDMAを抑止する.
ptop: バースト演算中に行うDMAの先頭アドレス.ロードの場合,バースト演算中に次回バースト演算に必要な入力がホスト主記憶からLMMに転送
される(プリフェッチ).ストアの場合,バースト演算中に前回バースト演算結果がLMMからホスト主記憶に転送される(遅延ドレイン).なお,
mapdist=0 の場合,同一 LMM を対象に,LD/ST とプリフェッチ/ドレインが同時動作する.
plen: 同じく長さ.単位は1word(4byte)である.
20220202
11
コンパイル過程 src/conv-mark/conv-mark の入力
void tone_curve(r, d, t)
unsigned int *r, *d;
unsigned char *t;
{
#if !defined(EMAX5) && !defined(EMAX6)
int j;
for (j=0; j<WD; j++) {
*d = ((t)[*r>>24])<<24 | (t[256+((*r>>16)&255)])<<16 | (t[512+((*r>>8)&255)])<<8;
r++; d++;
}
#else
Ull t1 = t;
Ull t2 = t+256;
Ull t3 = t+512;
Ull BR[16][4][4]; /* output registers in each unit */
Ull r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15;
Ull r16, r17, r18, r19, r20, r21, r22, r23, r24, r25, r26, r27, r28, r29, r30, r31;
int loop=WD;
//EMAX5A begin tone_curve mapdist=0
while (loop--) {
mop(OP_LDWR, 1, &BR[0][1][1], (Ull)(r++), 0LL, MSK_D0, (Ull)r, 320, 0, 0, (Ull)NULL, 320); /* stage#0 */
mop(OP_LDUBR, 1, &BR[1][1][1], (Ull)t1, BR[0][1][1], MSK_B3, (Ull)t1, 64, 0, 0, (Ull)NULL, 64); /* stage#1 */
mop(OP_LDUBR, 1, &BR[1][2][1], (Ull)t2, BR[0][1][1], MSK_B2, (Ull)t2, 64, 0, 0, (Ull)NULL, 64); /* stage#1 */
mop(OP_LDUBR, 1, &BR[1][3][1], (Ull)t3, BR[0][1][1], MSK_B1, (Ull)t3, 64, 0, 0, (Ull)NULL, 64); /* stage#1 */
exe(OP_MMRG, &r1, BR[1][1][1], EXP_H3210, BR[1][2][1], EXP_H3210, BR[1][3][1], EXP_H3210, OP_NOP, 0LL, OP_NOP, 0LL);
mop(OP_STWR, 3, &r1, (Ull)(d++), 0LL, MSK_D0, (Ull)d, 320, 0, 0, (Ull)NULL, 320); /* stage#2 */
}
//EMAX5A end
#endif
}
 filter+rmm.c
20220202
12
コンパイル過程 cpp –P の入力
 filter+rmm.c-mark.c
void tone_curve(r, d, t)
unsigned int *r, *d;
unsigned char *t;
{
#if !defined(EMAX5) && !defined(EMAX6)
int j;
for (j=0; j<WD; j++) {
*d = ((t)[*r>>24])<<24 | (t[256+((*r>>16)&255)])<<16 | (t[512+((*r>>8)&255)])<<8;
r++; d++;
}
#else
Ull t1 = t;
Ull t2 = t+256;
Ull t3 = t+512;
Ull BR[16][4][4]; /* output registers in each unit */
Ull r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15;
Ull r16, r17, r18, r19, r20, r21, r22, r23, r24, r25, r26, r27, r28, r29, r30, r31;
int loop=WD;
#define printf(format,...)
/-EMAX5AB-/ tone_curve 0
/-EMAX5AS-/ while (loop--) {
/-EMAX5AS-/ mop(OP_LDWR, 1, &BR[0][1][1], (Ull)(r++), 0LL, MSK_D0, (Ull)r, 320, 0, 0, (Ull)NULL, 320); /* stage#0 */
/-EMAX5AS-/ mop(OP_LDUBR, 1, &BR[1][1][1], (Ull)t1, BR[0][1][1], MSK_B3, (Ull)t1, 64, 0, 0, (Ull)NULL, 64); /* stage#1 */
/-EMAX5AS-/ mop(OP_LDUBR, 1, &BR[1][2][1], (Ull)t2, BR[0][1][1], MSK_B2, (Ull)t2, 64, 0, 0, (Ull)NULL, 64); /* stage#1 */
/-EMAX5AS-/ mop(OP_LDUBR, 1, &BR[1][3][1], (Ull)t3, BR[0][1][1], MSK_B1, (Ull)t3, 64, 0, 0, (Ull)NULL, 64); /* stage#1 */
/-EMAX5AS-/ exe(OP_MMRG, &r1, BR[1][1][1], EXP_H3210, BR[1][2][1], EXP_H3210, BR[1][3][1], EXP_H3210, OP_NOP, 0LL, OP_NOP, 0LL);
/-EMAX5AS-/ mop(OP_STWR, 3, &r1, (Ull)(d++), 0LL, MSK_D0, (Ull)d, 320, 0, 0, (Ull)NULL, 320); /* stage#2 */
/-EMAX5AS-/ }
/-EMAX5AE-/
#undef printf
#endif
}
20220202
13
コンパイル過程 src/conv-c2c/conv-c2c の入力
 filter+rmm.c-cppo.c
void tone_curve(r, d, t)
unsigned int *r, *d;
unsigned char *t;
{
Ull t1 = t;
Ull t2 = t+256;
Ull t3 = t+512;
Ull BR[16][4][4];
Ull r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15;
Ull r16, r17, r18, r19, r20, r21, r22, r23, r24, r25, r26, r27, r28, r29, r30, r31;
int loop=WD;
/-EMAX5AB-/ tone_curve 0
/-EMAX5AS-/ while (loop--) {
/-EMAX5AS-/ mop(0x02, 1, &BR[0][1][1], (Ull)(r++), 0LL, 14, (Ull)r, 320, 0, 0, (Ull)((void *)0), 320);
/-EMAX5AS-/ mop(0x07, 1, &BR[1][1][1], (Ull)t1, BR[0][1][1], 3, (Ull)t1, 64, 0, 0, (Ull)((void *)0), 64);
/-EMAX5AS-/ mop(0x07, 1, &BR[1][2][1], (Ull)t2, BR[0][1][1], 2, (Ull)t2, 64, 0, 0, (Ull)((void *)0), 64);
/-EMAX5AS-/ mop(0x07, 1, &BR[1][3][1], (Ull)t3, BR[0][1][1], 1, (Ull)t3, 64, 0, 0, (Ull)((void *)0), 64);
/-EMAX5AS-/ exe(0x25, &r1, BR[1][1][1], 3, BR[1][2][1], 3, BR[1][3][1], 3, 0x00, 0LL, 0x00, 0LL);
/-EMAX5AS-/ mop(0x12, 3, &r1, (Ull)(d++), 0LL, 14, (Ull)d, 320, 0, 0, (Ull)((void *)0), 320);
/-EMAX5AS-/ }
/-EMAX5AE-/
}
20220202
14
コンパイル過程 通常のARM-Cコンパイラの入力 1/3
 filter+rmm-emax6.c ../../src/conv-c2c/emax6.h ../../src/conv-c2c/emax6lib.c
void tone_curve(r, d, t)
unsigned int *r, *d;
unsigned char *t;
{
Ull t1 = t;
Ull t2 = t+256;
Ull t3 = t+512;
Ull BR[16][4][4];
Ull r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, r16, r17, r18, r19, r20, r21, r22, r23, r24, r25, r26, r27, r28, r29, r30, r31;
int loop=WD;
volatile emax6_conf_tone_curve();
emax6.lmmio = emax6.lmmic;
emax6.lmmic = 1-emax6.lmmic;
emax6.mapdist = 0;
*(Uint*)&emax6.lmmi[0][0][1][emax6.lmmic] = 0x013f0001|(0<<2);
emax6.lmmi[0][0][1][emax6.lmmic].ofs = 0; emax6.lmmi[0][0][1][emax6.lmmic].top = r;
*(Uint*)&emax6.lmmi[0][1][1][emax6.lmmic] = 0x003f0001|(0<<2);
emax6.lmmi[0][1][1][emax6.lmmic].ofs = 0; emax6.lmmi[0][1][1][emax6.lmmic].top = t1;
*(Uint*)&emax6.lmmi[0][1][2][emax6.lmmic] = 0x003f0001|(0<<2);
emax6.lmmi[0][1][2][emax6.lmmic].ofs = 0; emax6.lmmi[0][1][2][emax6.lmmic].top = t2;
*(Uint*)&emax6.lmmi[0][1][3][emax6.lmmic] = 0x003f0001|(0<<2);
emax6.lmmi[0][1][3][emax6.lmmic].ofs = 0; emax6.lmmi[0][1][3][emax6.lmmic].top = t3;
*(Uint*)&emax6.lmmi[0][2][0][emax6.lmmic] = 0x013f0003|(0<<2);
emax6.lmmi[0][2][0][emax6.lmmic].ofs = 0; emax6.lmmi[0][2][0][emax6.lmmic].top = d;
emax6.lmmi_bitmap[0] = 0x0000000000000004LL;
emax6.lmmi_bitmap[1] = 0x0000000000000003LL;
emax6.lmmi_bitmap[2] = 0x0000000000000002LL;
emax6.lmmi_bitmap[3] = 0x0000000000000002LL;
emax6_pre_with_drain_cache();
get_nanosec(NANOS_ARM);
if (emax6.last_conf == emax6_conf_tone_curve) {
emax6.status = STATUS_DRAIN;
emax6_check_lmmi_and_dma(0, 1, 0, 0, 2, 0);/*drain*/
}
get_nanosec(NANOS_DRAIN);
LMMのアドレス範囲情報
必要に応じて前回演算結果の回収
20220202
15
コンパイル過程 通常のARM-Cコンパイラの入力 2/3
if (emax6.last_conf != emax6_conf_tone_curve) {
Dll *dst, *src;
int i,j;
emax6.status = STATUS_CONF;
emax6.last_conf = emax6_conf_tone_curve;
emax6.lastdist = 0;
dst = (Dll*)(((struct reg_ctrl*)emax6.reg_ctrl)->i[0].conf);
src = (Dll*)emax6_conf_tone_curve;
for (i=0; i<sizeof(conf)/sizeof(Dll); i++)
*dst++ = *src++;
for (i=0; i<64; i++) {
for (j=0; j<4; j++)
emax6.lmmi[0][i][j][emax6.lmmio].v = 0;
}
while (((struct reg_ctrl*)emax6.reg_ctrl)->i[0].stat & 0xf0); //LMRING_BUSY
}
get_nanosec(NANOS_CONF);
emax6.status = STATUS_REGV;
((struct reg_ctrl*)emax6.reg_ctrl)->i[0].breg[63][0].br[0] = loop;
((struct reg_ctrl*)emax6.reg_ctrl)->i[0].breg[63][0].br[1] = -1LL;
((struct reg_ctrl*)emax6.reg_ctrl)->i[0].addr[0][1].ea1b = (Ull)r;
((struct reg_ctrl*)emax6.reg_ctrl)->i[0].addr[0][1].ea1o = (Ull)0LL;
((struct reg_ctrl*)emax6.reg_ctrl)->i[0].addr[1][1].ea1b = (Ull)t1;
((struct reg_ctrl*)emax6.reg_ctrl)->i[0].addr[1][2].ea1b = (Ull)t2;
((struct reg_ctrl*)emax6.reg_ctrl)->i[0].addr[1][3].ea1b = (Ull)t3;
((struct reg_ctrl*)emax6.reg_ctrl)->i[0].addr[2][0].ea0b = (Ull)d;
((struct reg_ctrl*)emax6.reg_ctrl)->i[0].addr[2][0].ea0o = (Ull)0LL;
get_nanosec(NANOS_REGV);
emax6.status = STATUS_RANGE;
{struct reg_ctrl *reg_ctrl = emax6.reg_ctrl;
Uint lmmic = emax6.lmmic;
*(Ull*)&(reg_ctrl->i[0].addr[0][1].top)=((Ull)(emax6.lmmi[0][0][1][lmmic].top+*((Ushort*)&emax6.lmmi[0][0][1][lmmic]+1)*sizeof(Uint)+(sizeof(Uint)-1))<<32)|(Ull)(Uint)emax6.lmmi[0][0][1][lm
*(Ull*)&(reg_ctrl->i[0].addr[1][1].top)=((Ull)(emax6.lmmi[0][1][1][lmmic].top+*((Ushort*)&emax6.lmmi[0][1][1][lmmic]+1)*sizeof(Uint)+(sizeof(Uint)-1))<<32)|(Ull)(Uint)emax6.lmmi[0][1][1][lm
*(Ull*)&(reg_ctrl->i[0].addr[1][2].top)=((Ull)(emax6.lmmi[0][1][2][lmmic].top+*((Ushort*)&emax6.lmmi[0][1][2][lmmic]+1)*sizeof(Uint)+(sizeof(Uint)-1))<<32)|(Ull)(Uint)emax6.lmmi[0][1][2][lm
*(Ull*)&(reg_ctrl->i[0].addr[1][3].top)=((Ull)(emax6.lmmi[0][1][3][lmmic].top+*((Ushort*)&emax6.lmmi[0][1][3][lmmic]+1)*sizeof(Uint)+(sizeof(Uint)-1))<<32)|(Ull)(Uint)emax6.lmmi[0][1][3][lm
*(Ull*)&(reg_ctrl->i[0].addr[2][0].top)=((Ull)(emax6.lmmi[0][2][0][lmmic].top+*((Ushort*)&emax6.lmmi[0][2][0][lmmic]+1)*sizeof(Uint)+(sizeof(Uint)-1))<<32)|(Ull)(Uint)emax6.lmmi[0][2][0][lm
}
get_nanosec(NANOS_RANGE);
命令写像が前回と異なる場合は
再写像
AXIIF/PIOによるレジスタ初期化
LMMにアドレス範囲情報書き込み
20220202
16
コンパイル過程 通常のARM-Cコンパイラの入力 3/3
emax6.status = STATUS_LOAD;
emax6_check_lmmi_and_dma(0, 2, emax6.lastdist, 0, 0, 1);/*load*/
emax6_check_lmmi_and_dma(0, 2, emax6.lastdist, 0, 1, 1);/*load*/
emax6_check_lmmi_and_dma(0, 2, emax6.lastdist, 0, 1, 2);/*load*/
emax6_check_lmmi_and_dma(0, 2, emax6.lastdist, 0, 1, 3);/*load*/
get_nanosec(NANOS_LOAD);
((struct reg_ctrl*)emax6.reg_ctrl)->i[0].cmd = 3LL; // EXEC
{struct reg_ctrl *reg_ctrl = emax6.reg_ctrl;
Uint lmmic = emax6.lmmic;
}
emax6.lmmd[2][0] = 0xff>>7;
while (((struct reg_ctrl*)emax6.reg_ctrl)->i[0].stat); //LMRING_BUSY|EXRING_BUSY
get_nanosec(NANOS_EXEC);
asm volatile("b emax6_conf_end_tone_curven"
".align 5n"
".global emax6_conf_tone_curven"
"emax6_conf_tone_curve:n"
" .word 0x031e0003, 0x00000000n"
" .word 0xffff0000, 0x00000000n"
" .word 0x00000000, 0x00000000n"
:
" .word 0xffff0000, 0x00000000n"
" .word 0x00000000, 0x00000000n"
" .word 0x00000000, 0x00000000n"
".global emax6_conf_end_tone_curven"
"emax6_conf_end_tone_curve:n"
);
}
AXIIF/DMAによる
LMMデータ書き込み
AXIIF/PIOによるIMAX起動
演算と同時の次データ転送が
あればDMA起動
UNITのconfiguration情報
ld @(gr1, 0) -> gr2
add gr1, 4 -> gr1
sub gr3, 1 -> gr3, z
VLIW0
add sub
gr1 gr3z
Register File
gr1 4 gr3 1
eag
gr1 4
0 1 2 3 4 5 6
0 0 0 0 0 0 0
0 1 2 3 4 5 6
0 0 0 0 0 0 0
0 1 2 3 4 5 6
0 0 0 0 0 0 0
0 1 2 3 4 5 6
0 0 0 0 0 0 0
0 1 2 3 4 5 6
0 0 0 0 0 0 0
z
0
z
0
z
0
z
0
z
0
gr2
ld
Propagation skip table
gr/cr
Stage
0
1
2
3
4
20220202
17
コンパイルが速いのは、非探索的だから
ld @(gr4, 0) -> gr5
add gr4, 4 -> gr4
bz end
VLIW1
add sub
gr1 gr3z
add
gr4
Register File
gr1 4
gr4 4
gr3 1 gr4
bz
end
eag
eag
gr1 4
gr4 4
0 1 2 3 4 5 6
0 1 1 1 0 0 0
0 1 2 3 4 5 6
0 1 1 1 0 0 0
0 1 2 3 4 5 6
0 0 1 0 0 0 0
0 1 2 3 4 5 6
0 0 0 0 0 0 0
0 1 2 3 4 5 6
0 0 0 0 0 0 0
z
1
z
1
z
0
z
0
z
0
gr5
ld
gr2
ld
Propagation skip table
gr/cr
Stage
0
1
2
3
4
VLIW1
20220202
18
LAPPと同様の非探索的高速コンパイル手法
gr5
ld
gr2
ld
sll gr2, 16 -> gr2
VLIW2
add sub
gr1 gr3z
add
gr4
sll
Register File
gr1 4
gr4 4
16
gr3 1
0 1 2 3 4 5 6
0 1 1 1 1 1 0
0 1 2 3 4 5 6
0 1 1 1 1 1 0
0 1 2 3 4 5 6
0 0 1 0 1 1 0
0 1 2 3 4 5 6
0 0 0 0 0 1 0
0 1 2 3 4 5 6
0 0 0 0 0 0 0
z
1
z
1
z
0
z
0
z
0
gr4
bz
end
eag
eag
gr1 4
gr4 4
Propagation skip table
gr/cr
Stage
0
1
2
3
4
VLIW2
VLIW2
20220202
19
LAPPと同様の非探索的高速コンパイル手法
gr5
ld
gr2
ld
or gr2, gr5 -> gr5
VLIW3
add sub
gr1 gr3z
add
gr4
gr2
Register File
or
gr5
gr1 4
gr4 4
gr3 1
0 1 2 3 4 5 6
0 1 1 1 1 1 0
0 1 2 3 4 5 6
0 1 1 1 1 1 0
0 1 2 3 4 5 6
0 0 1 0 1 1 0
0 1 2 3 4 5 6
0 0 1 0 0 1 0
0 1 2 3 4 5 6
0 0 0 0 0 0 0
z
1
z
1
z
0
z
0
z
0
gr4
bz
end
eag
eag
gr1 4
gr4 4
Propagation skip table
gr/cr
Stage
0
1
2
3
4
sll
16
VLIW3
VLIW3
VLIW3
20220202
20
LAPPと同様の非探索的高速コンパイル手法
gr5
gr2
ld
st, gr5 -> @(gr6, 0)
add gr6, 4 -> gr6
bra loop
VLIW4
add sub
gr1 gr3z
add
gr4
Register File
gr5 gr5
add
gr6
gr1 4
gr4 4
16
gr6
gr6 4
gr6
gr6
gr3 1
0 1 2 3 4 5 6
0 1 1 1 1 1 0
0 1 2 3 4 5 6
0 1 1 1 1 1 0
0 1 2 3 4 5 6
0 0 1 0 1 1 0
0 1 2 3 4 5 6
0 0 1 0 0 1 0
0 1 2 3 4 5 6
0 0 0 0 0 1 0
z
1
z
1
z
0
z
0
z
0
gr4 gr6
bz
bra
end
loop
eag
eag
eag
gr1 4
gr4 4
gr6 0
st
Propagation skip table
gr/cr
Stage
0
1
2
3
4
gr5
ld
gr2
or
sll
VLIW4
VLIW4
VLIW4
VLIW4
20220202
21
LAPPと同様の非探索的高速コンパイル手法
ZYNQ ZCU102 …ホストはARMv8-1.2GHz PL経由でIMAX-150MHzを実装
i7-8650U cross …ホストはx86_64 クロス開発環境
Jetson TX2 …ホストはARMv8-1.2GHz GPU使用,CUDA8.0に移植
Gold6144+V100 …ホストはx86_64 GPU使用,CUDA10.0に移植
(C)はCGLA記述とライブラリを用いた通常コンパイル
(IMAX)はCGLA記述と提案コンパイル手法
書き込みはNFS先,SDcardが影響?
20220202
22
コンパイル時間の比較
20220202
23
コンパイラの中身
/**********************************************************************************************************/
/* Step 1 ... decode[][]登録と伝搬レジスタ */
/* 1-1. 各insn[]のsrc毎に依存関係検査対象を抽出し,insn[].header.rdepと比較・rdepを下方へ更新 */
/* 1.2a 絶対位置指定★row,colがない場合(row=-1) */
/* 1.2b 絶対位置指定★row,colがある場合(row>=0) */
/* 1-3. 先行写像との競合検査 */
/* 1-4. insn[]->decode[][]コピーおよびALU機能割り当て可否検査 */
/* 1-5. busmap+伝搬レジスタ設定●emaxと異なり,更新変数は,同一行別カラムでの参照を禁止(逐次実行との互換) */
/* 1-6. 位置を確定.dst変数の位置情報をid[].row,colに記録 */
/**********************************************************************************************************/
/* Step 2 ... setup conf[][] */
/* 2-1. select EXE-in */
/* 2-2. select CEX-in and EAG-in */
/**********************************************************************************************************/
/* Step 3 ... setup conf[][] */
/* 3-1. select MW-in */
/* 3-2. select BR-in */
/* 3-3. set mapdist */
/**********************************************************************************************************/
/* Step 4 ... Insert LMM-buffering for neighbor LDDMQ. Multiple LDDMQ in the same row is not allowed */
/**********************************************************************************************************/
/* Step 5 ... Merge LMM imm_modeの初期値は,OP_IM_BUFRD/WRを含めて3 */
/* stage毎にcolumn間(3-2,1-0)を検査し,上記機能の干渉に応じてlmmを集約し,IM_PREF/DRAINと整合 */
/* 5-1. mode=0 | mode=0 1-0を検査し,#1/#0空 #0.mode=2/#1.mode=2(merge) */
/* 5-1. = 1-0を検査し,同一なら #1.mode=2&#0.mode=2(merge) */
/* 5-1. != 1-0を検査し,その他 #1.mode=3,#0.mode=3 */
/* 5-2. mode=0 | mode=0 3-2を検査し,#3/#2空 #2.mode=2/#3.mode=2(merge) */
/* 5-2. = 3-2を検査し,同一なら #3.mode=2&#2.mode=2(merge) */
/* 5-2. != 3-2を検査し,その他 #3.mode=3,#2.mode=3 */
/* 5-3. mode=0,0 | mode=0,0 (3-2)と(1-0)を検査し,#2.mode=2/#0.mode=2&空有なら,mode=1(merge) */
/* 5-3. mode=2 = mode=2 (3-2)と(1-0)を検査し,#2.mode=2&#0.mode=2&同一なら,mode=1(merge) */
/* 5-3. != (3-2)と(1-0)を検査し,その他, そのまま */
/* 5-4. mapdist!=0とmop=IM_PREF/DRAINの検出により対応IMの調整が可能 */
/* 一通りmode拡張後,最後に,幅の狭いほうにあわせて再分割する */
/**********************************************************************************************************/
/* Step 6 ... Set additional copy-flag for Vertical Broadcast(slave) */
/* 上から探して後段のvcopyを1にすると,lmf+lmxの場合,lmxがbitmapから消され,結果がDRAINされない */
/* 下から探して前段のvcopyを1にするのが正しい */
/**********************************************************************************************************/
/* Step 7 ... emit EMAX6 SC (soft-CGRA for manycore) */
/**********************************************************************************************************/
/* Step 8 ... emit EMAX6 CGRA */
/**********************************************************************************************************/
20220202
24
今回のおさらい

Weitere ähnliche Inhalte

Ähnlich wie PBL1-v1-010j.pptx

LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
Takeshi Yamamuro
 
HaskellではじめるCortex-M3組込みプログラミング
HaskellではじめるCortex-M3組込みプログラミングHaskellではじめるCortex-M3組込みプログラミング
HaskellではじめるCortex-M3組込みプログラミング
Kiwamu Okabe
 

Ähnlich wie PBL1-v1-010j.pptx (20)

Prosym2012
Prosym2012Prosym2012
Prosym2012
 
フラグを愛でる
フラグを愛でるフラグを愛でる
フラグを愛でる
 
Fftw誰得ガイド
Fftw誰得ガイドFftw誰得ガイド
Fftw誰得ガイド
 
V6でJIT・部分適用・継続
V6でJIT・部分適用・継続V6でJIT・部分適用・継続
V6でJIT・部分適用・継続
 
Kiso sekkei 01rev03
Kiso sekkei 01rev03Kiso sekkei 01rev03
Kiso sekkei 01rev03
 
平成25年社会人講座 Arduinoによるマイコン入門講座
平成25年社会人講座 Arduinoによるマイコン入門講座平成25年社会人講座 Arduinoによるマイコン入門講座
平成25年社会人講座 Arduinoによるマイコン入門講座
 
いにしえ的ななにか、カニか? RISC-V picoRV32, e203 改造 オレオレ命令追加した
いにしえ的ななにか、カニか? RISC-V picoRV32, e203 改造 オレオレ命令追加したいにしえ的ななにか、カニか? RISC-V picoRV32, e203 改造 オレオレ命令追加した
いにしえ的ななにか、カニか? RISC-V picoRV32, e203 改造 オレオレ命令追加した
 
Bluetooth通信の 仕組みと活用法紹介
Bluetooth通信の仕組みと活用法紹介Bluetooth通信の仕組みと活用法紹介
Bluetooth通信の 仕組みと活用法紹介
 
HPC Phys-20201203
HPC Phys-20201203HPC Phys-20201203
HPC Phys-20201203
 
20190625 OpenACC 講習会 第3部
20190625 OpenACC 講習会 第3部20190625 OpenACC 講習会 第3部
20190625 OpenACC 講習会 第3部
 
x86とコンテキストスイッチ
x86とコンテキストスイッチx86とコンテキストスイッチ
x86とコンテキストスイッチ
 
お前は PHP の歴史的な理由の数を覚えているのか
お前は PHP の歴史的な理由の数を覚えているのかお前は PHP の歴史的な理由の数を覚えているのか
お前は PHP の歴史的な理由の数を覚えているのか
 
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
 
Common LispでGPGPU
Common LispでGPGPUCommon LispでGPGPU
Common LispでGPGPU
 
PBL1-v1-011j.pptx
PBL1-v1-011j.pptxPBL1-v1-011j.pptx
PBL1-v1-011j.pptx
 
C++によるソート入門
C++によるソート入門C++によるソート入門
C++によるソート入門
 
HaskellではじめるCortex-M3組込みプログラミング
HaskellではじめるCortex-M3組込みプログラミングHaskellではじめるCortex-M3組込みプログラミング
HaskellではじめるCortex-M3組込みプログラミング
 
M5Stack互換機を作った話
M5Stack互換機を作った話M5Stack互換機を作った話
M5Stack互換機を作った話
 
Polyphony の行く末(2018/3/3)
Polyphony の行く末(2018/3/3)Polyphony の行く末(2018/3/3)
Polyphony の行く末(2018/3/3)
 
メンテできないコードをメンテする技術
メンテできないコードをメンテする技術メンテできないコードをメンテする技術
メンテできないコードをメンテする技術
 

Mehr von NAIST

Mehr von 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-010j.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 (10. 高速コンパイラ編)
  • 3. 20220819 3 FMA C+B*A ⇒ D Dual Random access
  • 4. 20220819 4 FMA C+B*A ⇒ D C has location info (next unit) D has location info (same as C) Sequential updates
  • 5. 20220819 5 FMA C+B*A ⇒ D D has location info (same as C) Sequential updates
  • 6. 20220819 6 FMA C+B*A ⇒ C Accumulation
  • 7. 20220202 7 命令テンプレート(自由記述は非効率、超CISC的表現が必要) cex(OP_CEXE, &ex0-9, c3, c2, c1, c0, 16bit-pattern) c3,c2,c2,c1は各々64bit値であり,bit32を連結した4bitと,bit0を連結した4bitにより,各々,16bit-patternのbit位置を 取り出した結果が,ex[0-9]のbit1およびbit0に格納される.ex0-9のbit1は条件付きストアの上位32bit,bit0は条件付きス トアの下位32bitに対応する. exe(OP_X, &var|&AR[0-63][0-3], s1, e1, s2, e2, s3, e3, OP_Y, s4, OP_Z, s5) ex4(OP_X, &var|&AR[0-63], s1, e1, s2, e2, s3, e3, OP_Y, s4, OP_Z, s5) varまたはAR[0-63][0-3]はALUの演算結果格納先であり,前者は位置情報無し,後者は行列位置情報に対応する.s1か らs3の各64bit値は,各々,e1からe3による修飾後に演算器に入力される.修飾子は以下の通り. EXP_H3210: 無加工 EXP_H1010: 下位32bitを上位+下位32bitにコピー EXP_H3232: 上位32bitを上位+下位32bitにコピー EXP_B5410: byte5,4,1,0を各々16bitに拡張し連結 EXP_B7632: byte7,6,3,2を各々16bitに拡張し連結 OP_Xには主に算術演算,OP_Yには主に論理演算,OP_Zには主にシフト演算を記述できる.各演算はSIMD型であり,上 位32bitと下位32bitを独立に扱う.exe()は倍幅、ex4()は8倍幅のSIMDである.
  • 8. 20220202 8 命令テンプレート exe(OP_X, &var, INIT0?var:var, e1, s2, e2, s3, e3, OP_Y, s4, OP_Z, s5) INIT0?var:varは,C言語としては常にvarであるため冗長である.これは,CGRAにおいてホストの介入無しに多重ループ に対応する工夫である.多重ループ起動前に,ホストは,内側ループに関する各初期値をCGRA内にセットする.通常, 内側ループ完了時にホストが介入して内部レジスタの再初期化を行う必要がある.しかし,IMAXでは,INIT0?var:varが 記述された変数は,CGRAが自ら再初期化を行い,ホスト介入のオーバヘッドを排除している.具体的には,varに初期値 がセットされていることを前提に,LOOP0の初回(INIT0=1)は,ホストが予めセットした当該初期値を演算器の第1入力とし, 次回以降は演算器出力を第1入力とするようデータパスを切替える. exe(OP_X, &var, var, e1, INIT0?s2:0, e2, s3, e3, OP_Y, s4, OP_Z, s5) これも,CGRAにおいて,ホストの介入無しに多重ループに対応する工夫である.INIT0?s2:0が記述されている場合, LOOP0の初回(INIT0=1)は,s2を演算器の第2入力とし,次回以降は0を第2入力とするようデータパスを切替える.2次元 サブアレイの先頭アドレス計算に利用できる.
  • 9. 20220202 9 命令テンプレート mex(OP MEX2, &s2, INIT0?s20:s2, INIT0?0:expr, OP MEX1, &s1, INIT0?s10:s1, INIT0?0:expr, limit, BR[0-63][0-3][1], BR[0-63][0-3][0]) ホストの介入無しに多重ループ疎行列計算またはマージソートを行うためのアドレス計算補助記述.INIT0?s20:s2 および INIT0?s10:s1 はベースアドレス,INIT0?0:expr は加算するオフセットに対応する.LOOP0 の初回 (INIT0=1) は,s2 と s1に, s20とs10(初期値)が格納され,次回以降は,前回ロー カルメモリから読み出した 2 つの64bitデータの上位32bitを比較し, 大小関係によって,s2またはs1,す なわちアドレス計算器出力に,0またはexprを加算した結果が格納される.また,limit はマージソート用の比較対象間距離である.使用方法はプログラム例を参照のこと.OP_MEX は以下の通り. OP_NOP: 常にbase OP_ALWAYS: 常にbase+offset OP_CMPA_LE: 上位32bit(BR[][][1])≦上位32bit(BR[][][0])ならbase+offset.それ以外はbase OP_CMPA_GE: 上位32bit(BR[][][1])≧上位32bit(BR[][][0])ならbase+offset.それ以外はbase?_
  • 10. 20220202 10 命令テンプレート mop(OP_X, ex9-0, &src|&dst, base, offset, mask, top, len, block, force, ptop, plen) mo4(OP_X, ex9-0, &src|&dst, base, offset, mask, top, len, block, force, ptop, plen) ローカルメモリに対するロードまたはストアを記述する.各項目は以下の通り. OP_X: データ幅に応じた倍幅SIMD型ロード命令またはストア命令.mo4は8倍幅SIMDである ex0-9: 無条件ストアの場合は定数3,前述の条件付きストアの場合は変数 src|dst: ロードの場合は格納先レジスタ,ストアの場合はストアデータ base: 参照するメモリアドレス base+mask(offset) のbase部分.ホストの主記憶アドレスをそのまま使える.ローカルメモリ内アドレスへはコンパイラと ハードウェアの連携により自動変換するので,アドレス変換を意識する必要はない offset: 同じくoffset部分.offsetの単位は1byteである点に注意 mask: 最終的なアドレスは,baseに,offsetレジスタをmaskにより修飾した値を加えたもの.MSK_B0:bit7-0、MSK_B1:bit15-8、MSK_B2:bit23-16、 MSK_B3:bit31-24、MSK_B4:bit39-32、MSK_B5:bit47-40、MSK_B6:bit55-48、MSK_B7:bit63-56、MSK_H0:bit15-0、MSK_H1:bit31-16、 MSK_H2:bit47-32、MSK_H3:bit63-48、MSK_W0:bit31-0、MSK_W1:bit63-32、MSK_D0:bit63-0 top: バースト演算が参照するホスト主記憶の先頭アドレス.先頭アドレスと長さを用いてホストDMAコントローラがホスト主記憶-LMM間転送を行う len: 同じく長さ.単位は1word(4byte)である.なお,DMA転送速度は256bit/cycleである.lenに定数0を指定した場合,topにより指定された領域が 確保されるものの,DMAは抑止される.この指定は,同一LMMによるダブルバッファリングを行う際に使用する. block: IMAXでは使用しない(EMAX5ではDMAギャザ機能のパラメタ) force: ロードとストアとで動作が異なる 0: ロードの場合,前回DMAの先頭アドレスおよび長さが同一であればDMAを起動せずLMMを再利用する.ストアの場合,バースト演算後に LMMからホスト主記憶にデータ転送する.ただし,次回バースト演算と同時の遅延ドレインが指定されている場合はDMAを抑止する. 1: ロードの場合,必ずホスト主記憶からLMMにデータ転送する.外部機器入力のように,アドレスが同じでも内容が異なる場合に使用する. ストアの場合,パーシャルストア(一部アドレスのみストア)を想定し,バースト演算前にホスト主記憶から一旦LMMにデータ転送する.ただし, 前回ストアとアドレス範囲が同じ場合はDMAを抑止する. ptop: バースト演算中に行うDMAの先頭アドレス.ロードの場合,バースト演算中に次回バースト演算に必要な入力がホスト主記憶からLMMに転送 される(プリフェッチ).ストアの場合,バースト演算中に前回バースト演算結果がLMMからホスト主記憶に転送される(遅延ドレイン).なお, mapdist=0 の場合,同一 LMM を対象に,LD/ST とプリフェッチ/ドレインが同時動作する. plen: 同じく長さ.単位は1word(4byte)である.
  • 11. 20220202 11 コンパイル過程 src/conv-mark/conv-mark の入力 void tone_curve(r, d, t) unsigned int *r, *d; unsigned char *t; { #if !defined(EMAX5) && !defined(EMAX6) int j; for (j=0; j<WD; j++) { *d = ((t)[*r>>24])<<24 | (t[256+((*r>>16)&255)])<<16 | (t[512+((*r>>8)&255)])<<8; r++; d++; } #else Ull t1 = t; Ull t2 = t+256; Ull t3 = t+512; Ull BR[16][4][4]; /* output registers in each unit */ Ull r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15; Ull r16, r17, r18, r19, r20, r21, r22, r23, r24, r25, r26, r27, r28, r29, r30, r31; int loop=WD; //EMAX5A begin tone_curve mapdist=0 while (loop--) { mop(OP_LDWR, 1, &BR[0][1][1], (Ull)(r++), 0LL, MSK_D0, (Ull)r, 320, 0, 0, (Ull)NULL, 320); /* stage#0 */ mop(OP_LDUBR, 1, &BR[1][1][1], (Ull)t1, BR[0][1][1], MSK_B3, (Ull)t1, 64, 0, 0, (Ull)NULL, 64); /* stage#1 */ mop(OP_LDUBR, 1, &BR[1][2][1], (Ull)t2, BR[0][1][1], MSK_B2, (Ull)t2, 64, 0, 0, (Ull)NULL, 64); /* stage#1 */ mop(OP_LDUBR, 1, &BR[1][3][1], (Ull)t3, BR[0][1][1], MSK_B1, (Ull)t3, 64, 0, 0, (Ull)NULL, 64); /* stage#1 */ exe(OP_MMRG, &r1, BR[1][1][1], EXP_H3210, BR[1][2][1], EXP_H3210, BR[1][3][1], EXP_H3210, OP_NOP, 0LL, OP_NOP, 0LL); mop(OP_STWR, 3, &r1, (Ull)(d++), 0LL, MSK_D0, (Ull)d, 320, 0, 0, (Ull)NULL, 320); /* stage#2 */ } //EMAX5A end #endif }  filter+rmm.c
  • 12. 20220202 12 コンパイル過程 cpp –P の入力  filter+rmm.c-mark.c void tone_curve(r, d, t) unsigned int *r, *d; unsigned char *t; { #if !defined(EMAX5) && !defined(EMAX6) int j; for (j=0; j<WD; j++) { *d = ((t)[*r>>24])<<24 | (t[256+((*r>>16)&255)])<<16 | (t[512+((*r>>8)&255)])<<8; r++; d++; } #else Ull t1 = t; Ull t2 = t+256; Ull t3 = t+512; Ull BR[16][4][4]; /* output registers in each unit */ Ull r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15; Ull r16, r17, r18, r19, r20, r21, r22, r23, r24, r25, r26, r27, r28, r29, r30, r31; int loop=WD; #define printf(format,...) /-EMAX5AB-/ tone_curve 0 /-EMAX5AS-/ while (loop--) { /-EMAX5AS-/ mop(OP_LDWR, 1, &BR[0][1][1], (Ull)(r++), 0LL, MSK_D0, (Ull)r, 320, 0, 0, (Ull)NULL, 320); /* stage#0 */ /-EMAX5AS-/ mop(OP_LDUBR, 1, &BR[1][1][1], (Ull)t1, BR[0][1][1], MSK_B3, (Ull)t1, 64, 0, 0, (Ull)NULL, 64); /* stage#1 */ /-EMAX5AS-/ mop(OP_LDUBR, 1, &BR[1][2][1], (Ull)t2, BR[0][1][1], MSK_B2, (Ull)t2, 64, 0, 0, (Ull)NULL, 64); /* stage#1 */ /-EMAX5AS-/ mop(OP_LDUBR, 1, &BR[1][3][1], (Ull)t3, BR[0][1][1], MSK_B1, (Ull)t3, 64, 0, 0, (Ull)NULL, 64); /* stage#1 */ /-EMAX5AS-/ exe(OP_MMRG, &r1, BR[1][1][1], EXP_H3210, BR[1][2][1], EXP_H3210, BR[1][3][1], EXP_H3210, OP_NOP, 0LL, OP_NOP, 0LL); /-EMAX5AS-/ mop(OP_STWR, 3, &r1, (Ull)(d++), 0LL, MSK_D0, (Ull)d, 320, 0, 0, (Ull)NULL, 320); /* stage#2 */ /-EMAX5AS-/ } /-EMAX5AE-/ #undef printf #endif }
  • 13. 20220202 13 コンパイル過程 src/conv-c2c/conv-c2c の入力  filter+rmm.c-cppo.c void tone_curve(r, d, t) unsigned int *r, *d; unsigned char *t; { Ull t1 = t; Ull t2 = t+256; Ull t3 = t+512; Ull BR[16][4][4]; Ull r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15; Ull r16, r17, r18, r19, r20, r21, r22, r23, r24, r25, r26, r27, r28, r29, r30, r31; int loop=WD; /-EMAX5AB-/ tone_curve 0 /-EMAX5AS-/ while (loop--) { /-EMAX5AS-/ mop(0x02, 1, &BR[0][1][1], (Ull)(r++), 0LL, 14, (Ull)r, 320, 0, 0, (Ull)((void *)0), 320); /-EMAX5AS-/ mop(0x07, 1, &BR[1][1][1], (Ull)t1, BR[0][1][1], 3, (Ull)t1, 64, 0, 0, (Ull)((void *)0), 64); /-EMAX5AS-/ mop(0x07, 1, &BR[1][2][1], (Ull)t2, BR[0][1][1], 2, (Ull)t2, 64, 0, 0, (Ull)((void *)0), 64); /-EMAX5AS-/ mop(0x07, 1, &BR[1][3][1], (Ull)t3, BR[0][1][1], 1, (Ull)t3, 64, 0, 0, (Ull)((void *)0), 64); /-EMAX5AS-/ exe(0x25, &r1, BR[1][1][1], 3, BR[1][2][1], 3, BR[1][3][1], 3, 0x00, 0LL, 0x00, 0LL); /-EMAX5AS-/ mop(0x12, 3, &r1, (Ull)(d++), 0LL, 14, (Ull)d, 320, 0, 0, (Ull)((void *)0), 320); /-EMAX5AS-/ } /-EMAX5AE-/ }
  • 14. 20220202 14 コンパイル過程 通常のARM-Cコンパイラの入力 1/3  filter+rmm-emax6.c ../../src/conv-c2c/emax6.h ../../src/conv-c2c/emax6lib.c void tone_curve(r, d, t) unsigned int *r, *d; unsigned char *t; { Ull t1 = t; Ull t2 = t+256; Ull t3 = t+512; Ull BR[16][4][4]; Ull r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, r16, r17, r18, r19, r20, r21, r22, r23, r24, r25, r26, r27, r28, r29, r30, r31; int loop=WD; volatile emax6_conf_tone_curve(); emax6.lmmio = emax6.lmmic; emax6.lmmic = 1-emax6.lmmic; emax6.mapdist = 0; *(Uint*)&emax6.lmmi[0][0][1][emax6.lmmic] = 0x013f0001|(0<<2); emax6.lmmi[0][0][1][emax6.lmmic].ofs = 0; emax6.lmmi[0][0][1][emax6.lmmic].top = r; *(Uint*)&emax6.lmmi[0][1][1][emax6.lmmic] = 0x003f0001|(0<<2); emax6.lmmi[0][1][1][emax6.lmmic].ofs = 0; emax6.lmmi[0][1][1][emax6.lmmic].top = t1; *(Uint*)&emax6.lmmi[0][1][2][emax6.lmmic] = 0x003f0001|(0<<2); emax6.lmmi[0][1][2][emax6.lmmic].ofs = 0; emax6.lmmi[0][1][2][emax6.lmmic].top = t2; *(Uint*)&emax6.lmmi[0][1][3][emax6.lmmic] = 0x003f0001|(0<<2); emax6.lmmi[0][1][3][emax6.lmmic].ofs = 0; emax6.lmmi[0][1][3][emax6.lmmic].top = t3; *(Uint*)&emax6.lmmi[0][2][0][emax6.lmmic] = 0x013f0003|(0<<2); emax6.lmmi[0][2][0][emax6.lmmic].ofs = 0; emax6.lmmi[0][2][0][emax6.lmmic].top = d; emax6.lmmi_bitmap[0] = 0x0000000000000004LL; emax6.lmmi_bitmap[1] = 0x0000000000000003LL; emax6.lmmi_bitmap[2] = 0x0000000000000002LL; emax6.lmmi_bitmap[3] = 0x0000000000000002LL; emax6_pre_with_drain_cache(); get_nanosec(NANOS_ARM); if (emax6.last_conf == emax6_conf_tone_curve) { emax6.status = STATUS_DRAIN; emax6_check_lmmi_and_dma(0, 1, 0, 0, 2, 0);/*drain*/ } get_nanosec(NANOS_DRAIN); LMMのアドレス範囲情報 必要に応じて前回演算結果の回収
  • 15. 20220202 15 コンパイル過程 通常のARM-Cコンパイラの入力 2/3 if (emax6.last_conf != emax6_conf_tone_curve) { Dll *dst, *src; int i,j; emax6.status = STATUS_CONF; emax6.last_conf = emax6_conf_tone_curve; emax6.lastdist = 0; dst = (Dll*)(((struct reg_ctrl*)emax6.reg_ctrl)->i[0].conf); src = (Dll*)emax6_conf_tone_curve; for (i=0; i<sizeof(conf)/sizeof(Dll); i++) *dst++ = *src++; for (i=0; i<64; i++) { for (j=0; j<4; j++) emax6.lmmi[0][i][j][emax6.lmmio].v = 0; } while (((struct reg_ctrl*)emax6.reg_ctrl)->i[0].stat & 0xf0); //LMRING_BUSY } get_nanosec(NANOS_CONF); emax6.status = STATUS_REGV; ((struct reg_ctrl*)emax6.reg_ctrl)->i[0].breg[63][0].br[0] = loop; ((struct reg_ctrl*)emax6.reg_ctrl)->i[0].breg[63][0].br[1] = -1LL; ((struct reg_ctrl*)emax6.reg_ctrl)->i[0].addr[0][1].ea1b = (Ull)r; ((struct reg_ctrl*)emax6.reg_ctrl)->i[0].addr[0][1].ea1o = (Ull)0LL; ((struct reg_ctrl*)emax6.reg_ctrl)->i[0].addr[1][1].ea1b = (Ull)t1; ((struct reg_ctrl*)emax6.reg_ctrl)->i[0].addr[1][2].ea1b = (Ull)t2; ((struct reg_ctrl*)emax6.reg_ctrl)->i[0].addr[1][3].ea1b = (Ull)t3; ((struct reg_ctrl*)emax6.reg_ctrl)->i[0].addr[2][0].ea0b = (Ull)d; ((struct reg_ctrl*)emax6.reg_ctrl)->i[0].addr[2][0].ea0o = (Ull)0LL; get_nanosec(NANOS_REGV); emax6.status = STATUS_RANGE; {struct reg_ctrl *reg_ctrl = emax6.reg_ctrl; Uint lmmic = emax6.lmmic; *(Ull*)&(reg_ctrl->i[0].addr[0][1].top)=((Ull)(emax6.lmmi[0][0][1][lmmic].top+*((Ushort*)&emax6.lmmi[0][0][1][lmmic]+1)*sizeof(Uint)+(sizeof(Uint)-1))<<32)|(Ull)(Uint)emax6.lmmi[0][0][1][lm *(Ull*)&(reg_ctrl->i[0].addr[1][1].top)=((Ull)(emax6.lmmi[0][1][1][lmmic].top+*((Ushort*)&emax6.lmmi[0][1][1][lmmic]+1)*sizeof(Uint)+(sizeof(Uint)-1))<<32)|(Ull)(Uint)emax6.lmmi[0][1][1][lm *(Ull*)&(reg_ctrl->i[0].addr[1][2].top)=((Ull)(emax6.lmmi[0][1][2][lmmic].top+*((Ushort*)&emax6.lmmi[0][1][2][lmmic]+1)*sizeof(Uint)+(sizeof(Uint)-1))<<32)|(Ull)(Uint)emax6.lmmi[0][1][2][lm *(Ull*)&(reg_ctrl->i[0].addr[1][3].top)=((Ull)(emax6.lmmi[0][1][3][lmmic].top+*((Ushort*)&emax6.lmmi[0][1][3][lmmic]+1)*sizeof(Uint)+(sizeof(Uint)-1))<<32)|(Ull)(Uint)emax6.lmmi[0][1][3][lm *(Ull*)&(reg_ctrl->i[0].addr[2][0].top)=((Ull)(emax6.lmmi[0][2][0][lmmic].top+*((Ushort*)&emax6.lmmi[0][2][0][lmmic]+1)*sizeof(Uint)+(sizeof(Uint)-1))<<32)|(Ull)(Uint)emax6.lmmi[0][2][0][lm } get_nanosec(NANOS_RANGE); 命令写像が前回と異なる場合は 再写像 AXIIF/PIOによるレジスタ初期化 LMMにアドレス範囲情報書き込み
  • 16. 20220202 16 コンパイル過程 通常のARM-Cコンパイラの入力 3/3 emax6.status = STATUS_LOAD; emax6_check_lmmi_and_dma(0, 2, emax6.lastdist, 0, 0, 1);/*load*/ emax6_check_lmmi_and_dma(0, 2, emax6.lastdist, 0, 1, 1);/*load*/ emax6_check_lmmi_and_dma(0, 2, emax6.lastdist, 0, 1, 2);/*load*/ emax6_check_lmmi_and_dma(0, 2, emax6.lastdist, 0, 1, 3);/*load*/ get_nanosec(NANOS_LOAD); ((struct reg_ctrl*)emax6.reg_ctrl)->i[0].cmd = 3LL; // EXEC {struct reg_ctrl *reg_ctrl = emax6.reg_ctrl; Uint lmmic = emax6.lmmic; } emax6.lmmd[2][0] = 0xff>>7; while (((struct reg_ctrl*)emax6.reg_ctrl)->i[0].stat); //LMRING_BUSY|EXRING_BUSY get_nanosec(NANOS_EXEC); asm volatile("b emax6_conf_end_tone_curven" ".align 5n" ".global emax6_conf_tone_curven" "emax6_conf_tone_curve:n" " .word 0x031e0003, 0x00000000n" " .word 0xffff0000, 0x00000000n" " .word 0x00000000, 0x00000000n" : " .word 0xffff0000, 0x00000000n" " .word 0x00000000, 0x00000000n" " .word 0x00000000, 0x00000000n" ".global emax6_conf_end_tone_curven" "emax6_conf_end_tone_curve:n" ); } AXIIF/DMAによる LMMデータ書き込み AXIIF/PIOによるIMAX起動 演算と同時の次データ転送が あればDMA起動 UNITのconfiguration情報
  • 17. ld @(gr1, 0) -> gr2 add gr1, 4 -> gr1 sub gr3, 1 -> gr3, z VLIW0 add sub gr1 gr3z Register File gr1 4 gr3 1 eag gr1 4 0 1 2 3 4 5 6 0 0 0 0 0 0 0 0 1 2 3 4 5 6 0 0 0 0 0 0 0 0 1 2 3 4 5 6 0 0 0 0 0 0 0 0 1 2 3 4 5 6 0 0 0 0 0 0 0 0 1 2 3 4 5 6 0 0 0 0 0 0 0 z 0 z 0 z 0 z 0 z 0 gr2 ld Propagation skip table gr/cr Stage 0 1 2 3 4 20220202 17 コンパイルが速いのは、非探索的だから
  • 18. ld @(gr4, 0) -> gr5 add gr4, 4 -> gr4 bz end VLIW1 add sub gr1 gr3z add gr4 Register File gr1 4 gr4 4 gr3 1 gr4 bz end eag eag gr1 4 gr4 4 0 1 2 3 4 5 6 0 1 1 1 0 0 0 0 1 2 3 4 5 6 0 1 1 1 0 0 0 0 1 2 3 4 5 6 0 0 1 0 0 0 0 0 1 2 3 4 5 6 0 0 0 0 0 0 0 0 1 2 3 4 5 6 0 0 0 0 0 0 0 z 1 z 1 z 0 z 0 z 0 gr5 ld gr2 ld Propagation skip table gr/cr Stage 0 1 2 3 4 VLIW1 20220202 18 LAPPと同様の非探索的高速コンパイル手法
  • 19. gr5 ld gr2 ld sll gr2, 16 -> gr2 VLIW2 add sub gr1 gr3z add gr4 sll Register File gr1 4 gr4 4 16 gr3 1 0 1 2 3 4 5 6 0 1 1 1 1 1 0 0 1 2 3 4 5 6 0 1 1 1 1 1 0 0 1 2 3 4 5 6 0 0 1 0 1 1 0 0 1 2 3 4 5 6 0 0 0 0 0 1 0 0 1 2 3 4 5 6 0 0 0 0 0 0 0 z 1 z 1 z 0 z 0 z 0 gr4 bz end eag eag gr1 4 gr4 4 Propagation skip table gr/cr Stage 0 1 2 3 4 VLIW2 VLIW2 20220202 19 LAPPと同様の非探索的高速コンパイル手法
  • 20. gr5 ld gr2 ld or gr2, gr5 -> gr5 VLIW3 add sub gr1 gr3z add gr4 gr2 Register File or gr5 gr1 4 gr4 4 gr3 1 0 1 2 3 4 5 6 0 1 1 1 1 1 0 0 1 2 3 4 5 6 0 1 1 1 1 1 0 0 1 2 3 4 5 6 0 0 1 0 1 1 0 0 1 2 3 4 5 6 0 0 1 0 0 1 0 0 1 2 3 4 5 6 0 0 0 0 0 0 0 z 1 z 1 z 0 z 0 z 0 gr4 bz end eag eag gr1 4 gr4 4 Propagation skip table gr/cr Stage 0 1 2 3 4 sll 16 VLIW3 VLIW3 VLIW3 20220202 20 LAPPと同様の非探索的高速コンパイル手法
  • 21. gr5 gr2 ld st, gr5 -> @(gr6, 0) add gr6, 4 -> gr6 bra loop VLIW4 add sub gr1 gr3z add gr4 Register File gr5 gr5 add gr6 gr1 4 gr4 4 16 gr6 gr6 4 gr6 gr6 gr3 1 0 1 2 3 4 5 6 0 1 1 1 1 1 0 0 1 2 3 4 5 6 0 1 1 1 1 1 0 0 1 2 3 4 5 6 0 0 1 0 1 1 0 0 1 2 3 4 5 6 0 0 1 0 0 1 0 0 1 2 3 4 5 6 0 0 0 0 0 1 0 z 1 z 1 z 0 z 0 z 0 gr4 gr6 bz bra end loop eag eag eag gr1 4 gr4 4 gr6 0 st Propagation skip table gr/cr Stage 0 1 2 3 4 gr5 ld gr2 or sll VLIW4 VLIW4 VLIW4 VLIW4 20220202 21 LAPPと同様の非探索的高速コンパイル手法
  • 22. ZYNQ ZCU102 …ホストはARMv8-1.2GHz PL経由でIMAX-150MHzを実装 i7-8650U cross …ホストはx86_64 クロス開発環境 Jetson TX2 …ホストはARMv8-1.2GHz GPU使用,CUDA8.0に移植 Gold6144+V100 …ホストはx86_64 GPU使用,CUDA10.0に移植 (C)はCGLA記述とライブラリを用いた通常コンパイル (IMAX)はCGLA記述と提案コンパイル手法 書き込みはNFS先,SDcardが影響? 20220202 22 コンパイル時間の比較
  • 23. 20220202 23 コンパイラの中身 /**********************************************************************************************************/ /* Step 1 ... decode[][]登録と伝搬レジスタ */ /* 1-1. 各insn[]のsrc毎に依存関係検査対象を抽出し,insn[].header.rdepと比較・rdepを下方へ更新 */ /* 1.2a 絶対位置指定★row,colがない場合(row=-1) */ /* 1.2b 絶対位置指定★row,colがある場合(row>=0) */ /* 1-3. 先行写像との競合検査 */ /* 1-4. insn[]->decode[][]コピーおよびALU機能割り当て可否検査 */ /* 1-5. busmap+伝搬レジスタ設定●emaxと異なり,更新変数は,同一行別カラムでの参照を禁止(逐次実行との互換) */ /* 1-6. 位置を確定.dst変数の位置情報をid[].row,colに記録 */ /**********************************************************************************************************/ /* Step 2 ... setup conf[][] */ /* 2-1. select EXE-in */ /* 2-2. select CEX-in and EAG-in */ /**********************************************************************************************************/ /* Step 3 ... setup conf[][] */ /* 3-1. select MW-in */ /* 3-2. select BR-in */ /* 3-3. set mapdist */ /**********************************************************************************************************/ /* Step 4 ... Insert LMM-buffering for neighbor LDDMQ. Multiple LDDMQ in the same row is not allowed */ /**********************************************************************************************************/ /* Step 5 ... Merge LMM imm_modeの初期値は,OP_IM_BUFRD/WRを含めて3 */ /* stage毎にcolumn間(3-2,1-0)を検査し,上記機能の干渉に応じてlmmを集約し,IM_PREF/DRAINと整合 */ /* 5-1. mode=0 | mode=0 1-0を検査し,#1/#0空 #0.mode=2/#1.mode=2(merge) */ /* 5-1. = 1-0を検査し,同一なら #1.mode=2&#0.mode=2(merge) */ /* 5-1. != 1-0を検査し,その他 #1.mode=3,#0.mode=3 */ /* 5-2. mode=0 | mode=0 3-2を検査し,#3/#2空 #2.mode=2/#3.mode=2(merge) */ /* 5-2. = 3-2を検査し,同一なら #3.mode=2&#2.mode=2(merge) */ /* 5-2. != 3-2を検査し,その他 #3.mode=3,#2.mode=3 */ /* 5-3. mode=0,0 | mode=0,0 (3-2)と(1-0)を検査し,#2.mode=2/#0.mode=2&空有なら,mode=1(merge) */ /* 5-3. mode=2 = mode=2 (3-2)と(1-0)を検査し,#2.mode=2&#0.mode=2&同一なら,mode=1(merge) */ /* 5-3. != (3-2)と(1-0)を検査し,その他, そのまま */ /* 5-4. mapdist!=0とmop=IM_PREF/DRAINの検出により対応IMの調整が可能 */ /* 一通りmode拡張後,最後に,幅の狭いほうにあわせて再分割する */ /**********************************************************************************************************/ /* Step 6 ... Set additional copy-flag for Vertical Broadcast(slave) */ /* 上から探して後段のvcopyを1にすると,lmf+lmxの場合,lmxがbitmapから消され,結果がDRAINされない */ /* 下から探して前段のvcopyを1にするのが正しい */ /**********************************************************************************************************/ /* Step 7 ... emit EMAX6 SC (soft-CGRA for manycore) */ /**********************************************************************************************************/ /* Step 8 ... emit EMAX6 CGRA */ /**********************************************************************************************************/

Hinweis der Redaktion

  1. 番組の途中ですが、コンパイラ、どうなってんの? という問い合わせが多いので、高速コンパイラ編です。なぜ、CGRAのコンパイルに、1秒しかかからないのか、仕組みを説明しましょう。
  2. 図、aからfは,アイマックスが対応している計算パターンをまとめたものです。山形はALU,長方形はローカルメモリを示していて,プログラムの視点では,4列構成です。aは,0の要素が少ない密行列を、8並列のSIMD命令で処理するパターンです。青色メモリから,一度に配列Aの連続8要素を読み出します。同様に,きいろメモリから配列Bの連続8要素,オレンジから配列Cの連続8要素を読み出します。そして,4個の3入力ALUが,ABCの各2要素を使って,A+B掛けるCを計算し,連続8要素の計算結果を赤色メモリに書き込みます。つまり,CGRAの1行あたり,8組のA+B掛けるCを計算します。bは,各ぎょう各メモリの離れた2箇所から,連続2要素を読み出し,縦に送って,多くの積和演算を行うパターンです。1列目と2列目のメモリを共有すれば,各配列の離れた4箇所から読み出せます。さらに,横1列のメモリを全て共有すれば,配列の離れた8箇所から読み出せます。cも,縦に送って,多くの積和演算を行うパターンです。ただし,最後の結果をメモリに書き込む時に,以前のあたいに1回だけ累算し,つぎの場所に移動します。メモリから読み出して,ぐるっと回して同じ場所に1回だけ書き戻します。dは,メモリの内容に1回だけ累算するのではなく,パイプライン演算器自身の演算結果を毎回戻して累算します。マルチスレッディングは,特にこのパターンにおいて,演算器稼働率を25%から100%に引き上げる仕組みです。eは,確率的積和演算のパターンです。アイマックスのデータパスはよく考えられていて,確率的計算機能を自然に入れることができます。配列AとBから、連続8ワードを読み出すことで,各8ビットのあたいを32個一度に読み出します。そして,8個ずつ,4つの確率的積和演算器に投入し,全ての結果を加算したあたいをメモリに書き込みます。fは,そ行列計算のパターンです。あらかじめ,64ビットの上位に要素番号,下位に要素値を格納することで,0の要素が多いそ行列を密行列に圧縮しておきます。アイマックスは,CGRAならではの,とても巧妙な、アドレス同調機構を使って,圧縮した行列どうしの行列積を計算します。マージソートもできます。メモリの有効利用と高速化が同時にできます。
  3. 図の青い部分が,アイマックスの論理ユニット1つ分です。ALU、2個のアドレス生成器、および、デュアルポートローカルメモリがあります。横に4つ並べて,1行4列分です。Bのランダムアクセスのプログラムを普通に書くと、配列ABCDの名前だけを用いて,2要素毎に“DイコールC+B掛けるA”を計算するプログラムになります。この場合、コンパイラは、アイマックスの1行目に、ロードA、ロードB、および、ロードCをセットし、2行目に、ABCを入力とする積和演算FMA、および、ストアDをセットします。普通のCGRAと同じように、上から下への単純なデータフローが形成されます。
  4. 一方、この図は,配列ABCを用いて,2要素毎に“DイコールC+B書けるA”を計算し,結果Dを配列Cに書き戻すケースです。ロードの格納先C、および、FMAの結果を一時格納する変数Dに、次のユニットを使うよう、位置情報を足すと、配列Cへのロードとストアを同時に行います。コンパイラは、アイマックスの1行目にロードA、ロードBをセットし,2行目にロードCをセットします。積和演算FMAの結果を、一時格納する変数Dが,Cと同一ぎょうに指定された場合、演算器の入力ABCは、一度、おなじぎょうの下側のレジスタに送られた後、演算器入力へ戻されます。配列Cに対するDのストアも、同一ぎょうにセットされるため、同じローカルメモリの配列Cに対する、ロード、演算、ストアとなります。
  5. 次の図は,1行に全てを収容するケースです。デュアルポートローカルメモリは,物理的には,アイマックスの1行につき、1個だけ装備されていて、じぶんかつたじゅうにより、最大4列分の独立した論理メモリに見せています。このため、まえのケースでは、1つの物理ローカルメモリを配列AとBで共有したのに対し、このケースでは、配列Cも共有します。おのおのの配列が使用可能なメモリ空間は減少します。それでも、1行に収容するメリットがある場合は、ロードの格納先Cには、位置情報を付加せず、FMAの結果を一時格納する変数Dのみに、位置情報を付加します。そうすると、ロードA、ロードB、ロードC、積和演算FMA、配列Cに対するDのストアが、すべて、おなじぎょうに写像されます。
  6. 最後の図は、一時変数Dを使用せず、積和演算FMAを“CイコールC+B掛けるA”と記述したケースです。ストアCには位置情報を付加しません。ローカルメモリにストアしたデータを、再度ロードする、積和演算の繰り返しになります。しかし、ストア後に、同一アドレスからロードして、演算に回す計算は、とても時間がかかるので、CPUでも回避しなければならないハードウェア動作の1つです。一方で、CGRAの場合、この動作は、演算器内のアキュムレート機能により、時間をかけずに容易に吸収できます、前のケースとの違いは、FMAが、単純なロード、演算、ストアではなく、入力C0が、ループの初回のみ、配列Cのロード結果に接続され、次回以降は、演算結果に接続され、アキュムレート、ストアの繰り返しとなる点です。もちろん、パイプライン浮動小数点演算器の場合、演算器内アキュムレートは、単独では毎サイクル実行が不可能です。アイマックスは、4列マルチスレッディングにより、このケースでも、論理ユニットの動作にオーバヘッドが生じないため、性能低下を心配することなく、プログラムを書けます。 以上のように、似たような積和演算でも、4種類の書き方があります。どれにするかを別に指定する方法を使えば,コンパイラは楽に作れます。でも,アイマックスのプログラムは,CPUでも動くことを重視しています。C言語の制約の中で正しく動き,かつ,アイマックス上で狙い通りに高速動作させるために、変数の依存関係に、位置情報を組み合わせたプログラミング手法としています。。
  7. ここからしばらくは,プログラミングに使う、テンプレートの説明です。アイマックス仕様書からの抜粋です。
  8. つづきです。
  9. つづきです。要するに、アイマックスのユニットは、スーパーシスクです。
  10. つづきです。ロードストア機能を記述する際には、データの入れ替えに関する情報が、もっとも重要です。コンパイラは、DMAに関する情報を元に、LMMに関する空間融合や、DMA最適化を行います。
  11. では、ソースプログラムが、どのように処理されていくかを見ていきましょう。これは,色を入れ換える簡単な画像処理プログラムです。まず,コンパイルの前に、まえ処理をします。コンブマークが変換します。
  12. 変換結果です。ぎょうの頭に,イーマックス5エービーという修飾が付いたり,中身が少し書き換えられています。次に,Cプリプロセッサ、cppが変換します。
  13. Cppの変換結果です。いげた部分がなくなりました。次に,アイマックスコンパイラの本体、コンブシーツーシーが、各ぎょうを解釈して、アイマックスのコードを生成します。
  14. コンパイル結果です。ワイルループの構造が消え,行数が増えて,一気に変わりました。各ローカルメモリの担当範囲の抽出,前回演算結果の回収,という具合に,アイマックスの制御コードが,CPUコードとして入りました。
  15. さらに,4列分の論理ユニット機能を物理ユニットにセット,初期値をレジスタファイルへセット,担当範囲情報を各ローカルメモリへセットします。
  16. 最後に,ローカルメモリへのデータ送信,アイマックスの起動,同時に次データの送信を行い,アイマックスの動作完了を待ちます。残りは,各ユニットに送られる機能情報です。
  17. この動画は、アイマックスの前身である、LAPPのハードウェアが,上から流れ込んでくるVLIWを、デコードし、レジスタ間依存関係に基づいて、CGRAの演算器間ネットワークをセットしていく様子です。探索が不要なアルゴリズムなので、ハードウェアが、動作周波数と同じ速度で高速にセットできます。アイマックスは、同じことをコンパイラがやっているだけです。ネットワーク設定ハードウェアがいらなくなるので、アイマックスのユニットは、LAPPのユニットよりも小さくなりました。
  18. さて、導入編で、FPGAとCGRAは、再構成の粒度が違うと言いました。ソースプログラムを入力として,FPGAコンパイラはゲート間接続情報,CGRAコンパイラはユニット間接続情報を生成します。FPGAの場合,アイマックス程度の大きな回路だと,合成に24時間以上かかります。一方、アイマックスのコンパイル時間は,デバッグ用に、アイマックス機能C言語ライブラリを使う場合でも,アイマックスコンパイラを使う場合でも,数秒です。
  19. コンブシーツーシーの中身は、こんな流れです。ソースコードをダウンロードできるので、詳細は、自分で確認しましょう。さっき説明した、演算器間ネットワークの構築だけでなく、ローカルメモリ空間を、たてよこにマージして、DMAを減らす機能が入っています。
  20. 今回は、アイマックスコンパイラの種明かしをしました。要するに、CGRAは、スーパーシスクにすることで、コンパイル時間を大幅に短縮できるということでした。では、今回はここまで。おつかれさま。