Seu SlideShare está sendo baixado. ×

# PBL1-v1-007j.pptx

Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Próximos SlideShares
PBL1-v1-006j.pptx
Carregando em…3
×

1 de 10 Anúncio

# PBL1-v1-007j.pptx

IMAX3: Amazing Dataflow-Centric CGRA and its Applications
I present this slide to all hungry engineers who are tired of CPU, GPU, FPGA, tensor core, AI core, who want some challenging one with no black box inside, and who want to improve by themselves.

IMAX3: Amazing Dataflow-Centric CGRA and its Applications
I present this slide to all hungry engineers who are tired of CPU, GPU, FPGA, tensor core, AI core, who want some challenging one with no black box inside, and who want to improve by themselves.

Anúncio
Anúncio

Anúncio

### PBL1-v1-007j.pptx

1. 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 （7. 逆行列編） スパコンからIoTまで 省エネ社会に AI+BCだけじゃない超効率計算手法
2. 2. 20220202 2 逆行列は、連立一次方程式の特殊ケースで求まる 連立一次方程式 LU分解 前進消去 後退代入
3. 3. 20220202 3 逆行列は、連立一次方程式の特殊ケースで求まる 連立一次方程式：Ax=bを解く 逆行列：bの列数を増やして単位行列にする xの列数が増えたものが逆行列 /* LU分解 */ for (i=0; i<M+1; i++) p[i] = i; for (i=0; i<M; i++) { pmax = 0.0; k = -1; for (j=i; j<M; j++) { if (pmax < fabsf(A[p[j]*M+i])) { pmax = fabsf(A[p[j]*M+i]); k = j; } } if (k == -1) { fprintf(stderr, "can't solven"); exit(1); } j = p[k]; p[k] = p[i]; p[i] = j; A[p[i]*M+i] = 1.0/A[p[i]*M+i]; for (j=i+1; j<M; j++) { A[p[j]*M+i] *= A[p[i]*M+i]; for (k=i+1; k<M; k++) A[p[j]*M+k] -= A[p[j]*M+i]*A[p[i]*M+k]; } } /* 逆行列求める */ for (i=0; i<M; i++) { for (j=0; j<M; j++) b[p[j]] = (i==j)?1.0:0.0; /*for (j=1; j<M; j++) { *//* 通常の連立一時方程式の場合*/ for (j=i+1; j<M; j++) { /* 逆行列(b[]=E)の場合,k<iではb[]==0なのでj=i+1から開始 */ /*for (k=0; k<j; k++) *//* 通常の連立一時方程式の場合*/ for (k=i; k<j; k++) /* 逆行列(b[]=E)の場合,k<iではb[]==0なのでk=iから開始 */ b[p[j]] -= A[p[j]*M+k]*b[p[k]]; } for (j=M-1; j>=0; j--) { for (k=M-1; k>j; k--) b[p[j]] -= A[p[j]*M+k]*x[k]; inv0[j*M+p[i]] = x[j] = b[p[j]]*A[p[j]*M+j]; } }
4. 4. 20220202 4 逆行列には、ローカルメモリ自己更新 /* LU分解 */ for (i=0; i<M+1; i++) p[i] = i; for (i=0; i<M; i++) { /* 列方向 */ pmax = 0.0; k = -1; for (j=i; j<M; j++) { /* 行方向に探索 */ if (pmax < fabsf(A[j*M+i])) { pmax = fabsf(A[j*M+i]); k = j; } } if (k == -1) { fprintf(stderr, "can't solven"); exit(1); } j = p[k]; p[k] = p[i]; p[i] = j; for (j=0; j<M; j++) { /* real pivotting */ /*★*/ tmp = A[k*M+j]; A[k*M+j] = A[i*M+j]; A[i*M+j] = tmp;/*★*/ } /*★*/ A[i*M+i] = 1.0/A[i*M+i]; /*★*/ for (j=i+1; j<M; j++) /* 行方向 */ A[j*M+i] *= A[i*M+i]; Uint *top = &A[i*M+i]; Uint *topw = (Ull)top; Uint len = M-i; Uint len2 = len+(RMGRP-1)*M; Uint grp; /* FPGA実機でj-loopの最終(len=1)が動かないので,ついでにARMのほうが速そうなlenをARMで実行 */ if (len < 16) { /* len<1でも正常なので性能最大化で決めてよい */ for (j=i+1; j<M; j+=NCHIP*H*RMGRP) { /* 行方向 */ for (CHIP=0; CHIP<NCHIP; CHIP++) { for (h=0; h<H; h++) { /* vertical (parallel) execution */ for (grp=0; grp<RMGRP; grp++) { for (k=0; k<M-(i+1); k++) { /* 最内列方向 */ if (j+h*NCHIP*RMGRP+CHIP*RMGRP+grp<M) A[(j+h*NCHIP*RMGRP+CHIP*RMGRP+grp)*M+i+1+k] -= A[(j+h*NCHIP*RMGRP+CHIP*RMGRP+grp)*M+i]*A[i*M+i+1+k]; } } } } } } else { for (j=i+1; j<M; j+=NCHIP*H*RMGRP) { /* 行方向 */ //EMAX5A begin inv_x1 mapdist=0 for (CHIP=0; CHIP<NCHIP; CHIP++) { for (INIT1=1,LOOP1=RMGRP,rofs=0-M*4; LOOP1--; INIT1=0) { /* stage#0 *//* mapped to FOR() on BR[63][1][0] */ for (INIT0=1,LOOP0=M-(i+1),cofs=0; LOOP0--; INIT0=0) { /* stage#0 *//* mapped to FOR() on BR[63][0][0] */ exe(OP_ADD, &cofs, INIT0?cofs:cofs, EXP_H3210, 4LL, EXP_H3210, 0LL, EXP_H3210, OP_AND, 0x00000000ffffffffLL, OP_NOP, 0LL); /* stage#0 */ exe(OP_ADD, &rofs, rofs, EXP_H3210, INIT0?M*4:0, EXP_H3210, 0LL, EXP_H3210, OP_NOP, 0LL, OP_NOP, 0LL); /* stage#0 */ exe(OP_ADD, &oofs, rofs, EXP_H3210, cofs, EXP_H3210, 0LL, EXP_H3210, OP_AND, 0x00000000ffffffffLL, OP_NOP, 0LL); /* stage#1 */ /***************************/ /* + - - - - - - - - - - - */ /* A[p[i]] 先頭行 */ /* 先頭行はi更新まで再利用可能 */ /* | * > > > > > > > > > > */ /* A[p[j]] 次行から引く */ /* 1行をLMMに写像 */ /* | v + - - - - - - - - - */ /* | v | * > > > > > > > > */ /* M/60を収容してi更新までj+=60を繰り返す *//* 行番号比較とcstによる端数制御 */ /* | v | v + - - - - - - - */ /* + CHIP#0 h=0 grp=0 */ /* | v | v - + - - - - - - */ /* + CHIP#0 h=0 grp=1 */ /* | v | v - - + - - - - - */ /* + CHIP#1 h=0 grp=0 */ /* | v | v - - - + - - - - */ /* + CHIP#1 h=0 grp=1 */ /* | v | v - - - - + - - - */ /* + CHIP#0 h=1 grp=0 */ /* | v | v - - - - - + - - */ /* + CHIP#0 h=1 grp=1 */ /* | v | v - - - - - - + - */ /* + CHIP#1 h=1 grp=0 */ /* | v | v - - - - - - - + */ /* + CHIP#1 h=1 grp=1 */ /***************************/ /* 最大60行まで写像可能 */ /* FOLDING時は,少なくとも第0列がFOLDINGであることが必要(conv-c2c仕様) */ /* CEXEにも関わらずSTWRの無意味なLMM入れ換えが発生するため,A[M][*](枠外領域)を使用 */ /* OK exe-loop */ exe(OP_CMP_LT, &cc0, l00[CHIP], EXP_H3210, M, EXP_H3210, 0LL, EXP_H3210, OP_NOP, 0LL, OP_NOP, 0); /* stage#1 LD */ mop(OP_LDWR, 1, &BR[2][2][1], top, cofs, MSK_W0, topw, len, 0, 0, NULL, len); /* A[p[i]*M+k] stage#2 | */ mop(OP_LDWR, 1, &BR[2][0][1], d00[CHIP], oofs, MSK_W0, d00w[CHIP], len2,0, 1, NULL, len2); /* A[p[j+h*NCHIP+CHIP]*M+k] stage#2 +-> | */ mop(OP_LDWR, 1, &BR[2][1][1], d00[CHIP], rofs, MSK_W0, d00w[CHIP], len2,0, 1, NULL, len2); /* A[p[j+h*NCHIP+CHIP]*M+k] stage#2 +-> | */ exe(OP_FMS, &AR[2][0], BR[2][0][1], EXP_H3210, BR[2][1][1], EXP_H3210, BR[2][2][1], EXP_H3210, OP_NOP, 0LL, OP_NOP, 0); /* stage#2 | ■■■ | 1.0 */ cex(OP_CEXE, &ex0, 0, 0, 0, cc0, 0xaaaa); /* stage#2 | AR[1] | */ mop(OP_STWR,ex0, &AR[2][0], oofs, d00[CHIP], MSK_D0, d00w[CHIP], len2, 0, 1, NULL, len2); /* stage#2 | + ST v */ #if (H>1) /* *--------- BR[2] */ exe(OP_CMP_LT, &cc1, l01[CHIP], EXP_H3210, M, EXP_H3210, 0LL, EXP_H3210, OP_NOP, 0LL, OP_NOP, 0); /* stage#2 LD */ mop(OP_LDWR, 1, &BR[3][2][1], top, cofs, MSK_W0, topw, len, 0, 0, NULL, len); /* A[p[i]*M+k] stage#3 | */ mop(OP_LDWR, 1, &BR[3][0][1], d01[CHIP], oofs, MSK_W0, d01w[CHIP], len2,0, 1, NULL, len2); /* A[p[j+h*NCHIP+CHIP]*M+k] stage#3 +-> | */ mop(OP_LDWR, 1, &BR[3][1][1], d01[CHIP], rofs, MSK_W0, d01w[CHIP], len2,0, 1, NULL, len2); /* A[p[j+h*NCHIP+CHIP]*M+k] stage#3 +-> | */ exe(OP_FMS, &AR[3][0], BR[3][0][1], EXP_H3210, BR[3][1][1], EXP_H3210, BR[3][2][1], EXP_H3210, OP_NOP, 0LL, OP_NOP, 0); /* stage#3 | ■■■ | 1.0 */ cex(OP_CEXE, &ex0, 0, 0, 0, cc1, 0xaaaa); /* stage#3 | AR[2] | */ mop(OP_STWR,ex0, &AR[3][0], oofs, d01[CHIP], MSK_D0, d01w[CHIP], len2, 0, 1, NULL, len2); /* stage#3 | + ST v */ #if (H>2) /* *--------- BR[3] */ exe(OP_CMP_LT, &cc0, l02[CHIP], EXP_H3210, M, EXP_H3210, 0LL, EXP_H3210, OP_NOP, 0LL, OP_NOP, 0); /* stage#3 LD */ mop(OP_LDWR, 1, &BR[4][2][1], top, cofs, MSK_W0, topw, len, 0, 0, NULL, len); /* A[p[i]*M+k] stage#1 stage#4 | */ mop(OP_LDWR, 1, &BR[4][0][1], d02[CHIP], oofs, MSK_W0, d02w[CHIP], len2,0, 1, NULL, len2); /* A[p[j+h*NCHIP+CHIP]*M+k] stage#4 +-> | */ mop(OP_LDWR, 1, &BR[4][1][1], d02[CHIP], rofs, MSK_W0, d02w[CHIP], len2,0, 1, NULL, len2); /* A[p[j+h*NCHIP+CHIP]*M+k] stage#4 +-> | */ exe(OP_FMS, &AR[4][0], BR[4][0][1], EXP_H3210, BR[4][1][1], EXP_H3210, BR[4][2][1], EXP_H3210, OP_NOP, 0LL, OP_NOP, 0); /* stage#4 | ■■■ | 1.0 */ cex(OP_CEXE, &ex0, 0, 0, 0, cc0, 0xaaaa); /* stage#4 | AR[3] | */ mop(OP_STWR,ex0, &AR[4][0], oofs, d02[CHIP], MSK_D0, d02w[CHIP], len2, 0, 1, NULL, len2); /* stage#4 | + ST v */ #if (H>3) /* *--------- BR[4] */ exe(OP_CMP_LT, &cc1, l03[CHIP], EXP_H3210, M, EXP_H3210, 0LL, EXP_H3210, OP_NOP, 0LL, OP_NOP, 0); /* stage#4 LD */ mop(OP_LDWR, 1, &BR[5][2][1], top, cofs, MSK_W0, topw, len, 0, 0, NULL, len); /* A[p[i]*M+k] stage#1 stage#5 | */ mop(OP_LDWR, 1, &BR[5][0][1], d03[CHIP], oofs, MSK_W0, d03w[CHIP], len2,0, 1, NULL, len2); /* A[p[j+h*NCHIP+CHIP]*M+k] stage#5 +-> | */ mop(OP_LDWR, 1, &BR[5][1][1], d03[CHIP], rofs, MSK_W0, d03w[CHIP], len2,0, 1, NULL, len2); /* A[p[j+h*NCHIP+CHIP]*M+k] stage#5 +-> | */ exe(OP_FMS, &AR[5][0], BR[5][0][1], EXP_H3210, BR[5][1][1], EXP_H3210, BR[5][2][1], EXP_H3210, OP_NOP, 0LL, OP_NOP, 0); /* stage#5 | ■■■ | 1.0 */ cex(OP_CEXE, &ex0, 0, 0, 0, cc1, 0xaaaa); /* stage#5 | AR[4] | */ mop(OP_STWR,ex0, &AR[5][0], oofs, d03[CHIP], MSK_D0, d03w[CHIP], len2, 0, 1, NULL, len2); /* stage#5 | + ST v */ #endif #endif #endif } } } //EMAX5A end } /* j-loop */ //EMAX5A drain_dirty_lmm } /* else */ }
5. 5. 20220202 5 逆行列には、ローカルメモリ自己更新 for (j=i+1; j<M; j+=NCHIP*H*RMGRP) { /* 行方向 */ //EMAX5A begin inv_x1 mapdist=0 for (CHIP=0; CHIP<NCHIP; CHIP++) { for (INIT1=1,LOOP1=RMGRP,rofs=0-M*4; LOOP1--; INIT1=0) { /* stage#0 *//* mapped to FOR() on BR[63][1][0] */ for (INIT0=1,LOOP0=M-(i+1),cofs=0; LOOP0--; INIT0=0) { /* stage#0 *//* mapped to FOR() on BR[63][0][0] */ exe(OP_ADD, &cofs, INIT0?cofs:cofs, EXP_H3210, 4LL, EXP_H3210, 0LL, EXP_H3210, OP_AND, 0x00000000ffffffffLL, OP_NOP, 0LL); /* stage#0 */ exe(OP_ADD, &rofs, rofs, EXP_H3210, INIT0?M*4:0, EXP_H3210, 0LL, EXP_H3210, OP_NOP, 0LL, OP_NOP, 0LL); /* stage#0 */ exe(OP_ADD, &oofs, rofs, EXP_H3210, cofs, EXP_H3210, 0LL, EXP_H3210, OP_AND, 0x00000000ffffffffLL, OP_NOP, 0LL); /* stage#1 */ /***************************/ /* + - - - - - - - - - - - */ /* A[p[i]] 先頭行 */ /* 先頭行はi更新まで再利用可能 */ /* | * > > > > > > > > > > */ /* A[p[j]] 次行から引く */ /* 1行をLMMに写像 */ /* | v + - - - - - - - - - */ /* | v | * > > > > > > > > */ /* M/60を収容してi更新までj+=60を繰り返す *//* 行番号比較とcstによる端数制御 */ /* | v | v + - - - - - - - */ /* + CHIP#0 h=0 grp=0 */ /* | v | v - + - - - - - - */ /* + CHIP#0 h=0 grp=1 */ /* | v | v - - + - - - - - */ /* + CHIP#1 h=0 grp=0 */ /* | v | v - - - + - - - - */ /* + CHIP#1 h=0 grp=1 */ /* | v | v - - - - + - - - */ /* + CHIP#0 h=1 grp=0 */ /* | v | v - - - - - + - - */ /* + CHIP#0 h=1 grp=1 */ /* | v | v - - - - - - + - */ /* + CHIP#1 h=1 grp=0 */ /* | v | v - - - - - - - + */ /* + CHIP#1 h=1 grp=1 */ /***************************/ /* 最大60行まで写像可能 */ /* FOLDING時は,少なくとも第0列がFOLDINGであることが必要(conv-c2c仕様) */ /* CEXEにも関わらずSTWRの無意味なLMM入れ換えが発生するため,A[M][*](枠外領域)を使用 */ /* OK exe-loop */ exe(OP_CMP_LT, &cc0, l00[CHIP], EXP_H3210, M, EXP_H3210, 0LL, EXP_H3210, OP_NOP, 0LL, OP_NOP, 0); /* stage#1 LD */ mop(OP_LDWR, 1, &BR[2][2][1], top, cofs, MSK_W0, topw, len, 0, 0, NULL, len); /* A[p[i]*M+k] stage#2 | */ mop(OP_LDWR, 1, &BR[2][0][1], d00[CHIP], oofs, MSK_W0, d00w[CHIP], len2,0, 1, NULL, len2); /* A[p[j+h*NCHIP+CHIP]*M+k] stage#2 +-> | */ mop(OP_LDWR, 1, &BR[2][1][1], d00[CHIP], rofs, MSK_W0, d00w[CHIP], len2,0, 1, NULL, len2); /* A[p[j+h*NCHIP+CHIP]*M+k] stage#2 +-> | */ exe(OP_FMS, &AR[2][0], BR[2][0][1], EXP_H3210, BR[2][1][1], EXP_H3210, BR[2][2][1], EXP_H3210, OP_NOP, 0LL, OP_NOP, 0); /* stage#2 | ■■■ | 1.0 */ cex(OP_CEXE, &ex0, 0, 0, 0, cc0, 0xaaaa); /* stage#2 | AR[1] | */ mop(OP_STWR,ex0, &AR[2][0], oofs, d00[CHIP], MSK_D0, d00w[CHIP], len2, 0, 1, NULL, len2); /* stage#2 | + ST v */ #if (H>1) /* *--------- BR[2] */ exe(OP_CMP_LT, &cc1, l01[CHIP], EXP_H3210, M, EXP_H3210, 0LL, EXP_H3210, OP_NOP, 0LL, OP_NOP, 0); /* stage#2 LD */ mop(OP_LDWR, 1, &BR[3][2][1], top, cofs, MSK_W0, topw, len, 0, 0, NULL, len); /* A[p[i]*M+k] stage#3 | */ mop(OP_LDWR, 1, &BR[3][0][1], d01[CHIP], oofs, MSK_W0, d01w[CHIP], len2,0, 1, NULL, len2); /* A[p[j+h*NCHIP+CHIP]*M+k] stage#3 +-> | */ mop(OP_LDWR, 1, &BR[3][1][1], d01[CHIP], rofs, MSK_W0, d01w[CHIP], len2,0, 1, NULL, len2); /* A[p[j+h*NCHIP+CHIP]*M+k] stage#3 +-> | */ exe(OP_FMS, &AR[3][0], BR[3][0][1], EXP_H3210, BR[3][1][1], EXP_H3210, BR[3][2][1], EXP_H3210, OP_NOP, 0LL, OP_NOP, 0); /* stage#3 | ■■■ | 1.0 */ cex(OP_CEXE, &ex0, 0, 0, 0, cc1, 0xaaaa); /* stage#3 | AR[2] | */ mop(OP_STWR,ex0, &AR[3][0], oofs, d01[CHIP], MSK_D0, d01w[CHIP], len2, 0, 1, NULL, len2); /* stage#3 | + ST v */ #if (H>2) /* *--------- BR[3] */ if (j+h*NCHIP*RMGRP+CHIP*RMGRP+grp<M) A[(j+h*NCHIP*RMGRP+CHIP*RMGRP+grp)*M+i+1+k] -= A[(j+h*NCHIP*RMGRP+CHIP*RMGRP+grp)*M+i]*A[i*M+i+1+k];
6. 6. 20220202 6 条件付きストア機能を使う exe(OP_CMP_LT, &cc0, l00[CHIP], EXP_H3210, M, EXP_H3210, 0LL, mop(OP_LDWR, 1, &BR[2][2][1], top, cofs, MSK_W0, topw, len, 0, 0, NULL, len); mop(OP_LDWR, 1, &BR[2][0][1], d00[CHIP], oofs, MSK_W0, d00w[CHIP], len2,0, 1, NULL, len2); mop(OP_LDWR, 1, &BR[2][1][1], d00[CHIP], rofs, MSK_W0, d00w[CHIP], len2,0, 1, NULL, len2); exe(OP_FMS, &AR[2][0], BR[2][0][1], EXP_H3210, BR[2][1][1], EXP_H3210, BR[2][2][1], cex(OP_CEXE, &ex0, 0, 0, 0, cc0, 0xaaaa ); mop(OP_STWR, ex0, &AR[2][0], oofs, d00[CHIP], MSK_D0, d00w[CHIP], len2, 0, 1, NULL, len2); 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
7. 7. 20220202 7 逆行列には、ローカルメモリ自己更新 /* 前進消去 */ for (i=0; i<M; i++) { /* 列方向 */ for (j=0; j<M; j++) /* 行方向 */ b[i*M+j] = (i==j)?1.0:0.0; } for (i=0; i<M; i+=NCHIP*H) { /* 列方向 */ /*for (j=1; j<M; j++) { *//*通常の連立一時方程式の場合*/ for (j=i+1; j<M; j++) { /* 逆行列(b[]=E)の場合,k<iではb[]==0なのでj=i+1から開始 */ Uint *top = &A[j*M+i]; /* A[p[j]*M+k] */ Uint *topw = (Ull)top; /*Uint len = (j+1)/2;*/ Uint len = j-i;/* bが単位行列の場合,k<iではb[]==0なのでk=iから開始 */ /********************************************/ if (len < 16) { /* len<1でも正常なので性能最大化で決めてよい */ for (CHIP=0; CHIP<NCHIP; CHIP++) { for (h=0; h<H; h++) { /* vertical (parallel) execution */ /*for (k=0; k<j; k++) { *//*通常の連立一時方程式の場合*/ for (k=i; k<j; k++) { /* 逆行列(b[]=E)の場合,k<iではb[]==0なのでk=iから開始 */ b[(i+CHIP*H+h)*M+j] -= A[j*M+k]*b[(i+CHIP*H+h)*M+k]; } } } } else { Uint jc = j-i; //EMAX5A begin inv_x2 mapdist=0 for (CHIP=0; CHIP<NCHIP; CHIP++) { for (INIT0=1,LOOP0=jc,cofs=0-4; LOOP0--; INIT0=0) { /* stage#0 *//* mapped to FOR() on BR[63][0][0] */ exe(OP_ADD, &cofs, cofs, EXP_H3210, 4LL, EXP_H3210, 0LL, EXP_H3210, OP_AND, 0x00000000ffffffffLL, OP_NOP, 0LL); /* stage#0 */ mop(OP_LDWR, 1, &Ajk, top, cofs, MSK_W0, topw, len, 0, 0, NULL, len); /* A[p[j]*M+k] *//* stage#1.0 */ mop(OP_LDWR, 1, &BR[1][3][1], t000[CHIP], cofs, MSK_W0, t000w[CHIP], len, 0, 1, NULL, len); /* b[(i+CHIP*W*H+h*W+0)*M+k] *//* stage#1.3 +->xxx LD */ mop(OP_LDWR, 1, &b000, d000[CHIP], 0, MSK_W0, d000w[CHIP], 1, 0, 1, NULL, 1); /* b[(i+CHIP*W*H+h*W+0)*M+j] *//* stage#2.0 | ■■■ | */ exe(OP_FMS, &b000, b000, EXP_H3210, Ajk, EXP_H3210, BR[1][3][1], EXP_H3210, OP_NOP, 0LL, OP_NOP, 0LL); /* stage#2.0 +- xxx+ST v */ mop(OP_STWR, 1, &b000, 0, d000[CHIP], MSK_D0, d000w[CHIP], 1, 0, 1, NULL, 1); /* stage#2.0 +--------- xxx */ #if (H>1) mop(OP_LDWR, 1, &BR[2][3][1], t010[CHIP], cofs, MSK_W0, t010w[CHIP], len, 0, 1, NULL, len); /* b[(i+CHIP*W*H+h*W+0)*M+k] *//* stage#2.3 +->xxx LD */ mop(OP_LDWR, 1, &b000, d010[CHIP], 0, MSK_W0, d010w[CHIP], 1, 0, 1, NULL, 1); /* b[(i+CHIP*W*H+h*W+0)*M+j] *//* stage#3.0 | ■■■ | */ exe(OP_FMS, &b000, b000, EXP_H3210, Ajk, EXP_H3210, BR[2][3][1], EXP_H3210, OP_NOP, 0LL, OP_NOP, 0LL); /* stage#3.0 +- xxx+ST v */ mop(OP_STWR, 1, &b000, 0, d010[CHIP], MSK_D0, d010w[CHIP], 1, 0, 1, NULL, 1); /* stage#3.0 +--------- xxx */ #if (H>2) ： #endif #endif } } //EMAX5A end //EMAX5A drain_dirty_lmm } /* else */ /********************************************/ } /* j-loop */ }
8. 8. 20220202 8 逆行列には、ローカルメモリ自己更新 /* 後退代入 */ for (i=0; i<M; i+=NCHIP*H) { /* 列方向 */ for (j=M-1; j>=0; j--) { /* 行方向 */ if (j<M-1) { Uint *top = &A[j*M+j+1]; /* A[p[j]*M+k] */ Uint *topw = (Ull)top; Uint len = M-j-1; /********************************************/ if (len < 16) { /* len<1でも正常なので性能最大化で決めてよい */ for (CHIP=0; CHIP<NCHIP; CHIP++) { for (h=0; h<H; h++) { /* vertical (parallel) execution */ for (k=M-1; k>j; k--) { /* 最内列方向 */ b[(i+CHIP*H+h)*M+j] -= A[j*M+k]*x[(i+CHIP*H+h)*M+k]; } } } } else { Uint jc = M-j-1; //EMAX5A begin inv_x3 mapdist=0 for (CHIP=0; CHIP<NCHIP; CHIP++) { for (INIT0=1,LOOP0=jc,cofs=jc*4; LOOP0--; INIT0=0) { /* stage#0 *//* mapped to FOR() on BR[63][0][0] */ exe(OP_ADD, &cofs, cofs, EXP_H3210, -4, EXP_H3210, 0LL, EXP_H3210, OP_AND, 0x00000000ffffffffLL, OP_NOP, 0LL); /* stage#0 */ mop(OP_LDWR, 1, &Ajk, top, cofs, MSK_W0, topw, len, 0, 0, NULL, len); /* A[p[j]*M+k] *//* */ mop(OP_LDWR, 1, &BR[1][3][1], t000[CHIP], cofs, MSK_W0, t000w[CHIP], len, 0, 1, NULL, len); /* b[(i+CHIP*W*H+h*W+0)*M+k] *//* stage#1.3 +->xxx LD *//*read-modify-w*/ mop(OP_LDWR, 1, &b000, d000[CHIP], 0, MSK_W0, d000w[CHIP], 1, 0, 1, NULL, 1); /* b[(i+CHIP*W*H+h*W+0)*M+j] *//* stage#2.0 | ■■■ | */ exe(OP_FMS, &b000, b000, EXP_H3210, Ajk, EXP_H3210, BR[1][3][1], EXP_H3210, OP_NOP, 0LL, OP_NOP, 0LL); /* stage#2.0 +- xxx+ST v */ mop(OP_STWR, 1, &b000, 0, d000[CHIP], MSK_D0, d000w[CHIP], 1, 0, 1, NULL, 1); /* stage#2.0 +--------- xxx */ #if (H>1) mop(OP_LDWR, 1, &BR[2][3][1], t010[CHIP], cofs, MSK_W0, t010w[CHIP], len, 0, 1, NULL, len); /* b[(i+CHIP*W*H+h*W+0)*M+k] *//* stage#2.3 +->xxx LD *//*read-modify-w*/ mop(OP_LDWR, 1, &b000, d010[CHIP], 0, MSK_W0, d010w[CHIP], 1, 0, 1, NULL, 1); /* b[(i+CHIP*W*H+h*W+0)*M+j] *//* stage#3.0 | ■■■ | */ exe(OP_FMS, &b000, b000, EXP_H3210, Ajk, EXP_H3210, BR[2][3][1], EXP_H3210, OP_NOP, 0LL, OP_NOP, 0LL); /* stage#3.0 +- xxx+ST v */ mop(OP_STWR, 1, &b000, 0, d010[CHIP], MSK_D0, d010w[CHIP], 1, 0, 1, NULL, 1); /* stage#3.0 +--------- xxx */ #if (H>2) ： #endif #endif } } //EMAX5A end //EMAX5A drain_dirty_lmm } /* else */ /********************************************/ } /* if (j<M-1) */ for (CHIP=0; CHIP<NCHIP; CHIP++) { for (h=0; h<H; h++) { /* vertical (parallel) execution */ inv1[j*M+p[i+CHIP*H+h]] = x[(i+CHIP*H+h)*M+j] = A[j*M+j]*b[(i+CHIP*H+h)*M+j]; /* PIOにてLMMのx[i*M+j]を直接更新 *//* iはそのままで,jを切替え */ } } } /* j-loop */ }
9. 9. 20220202 9 コンパイル結果
10. 10. 20220202 10 今回のおさらい

### Notas do Editor

• 様々なアプリケーションを取りあげて、アイマックスのポテンシャルを説明するシリーズです。第7回は、逆行列です。
• みなさんは、Axイコールbを解いて、xを求める、連立一次方程式の解法を知っていますね。
bの列数を増やして単位行列にすれば、Xの列数が増えて逆行列が求まります。
LU分解を使って、連立一次方程式を解けるので、このアルゴリズムを列方向に拡張すればOKです。
• このCプログラムは、左でLU分解し、右で逆行列を求めています。連立一次方程式のコードが、青字のコメントに残してあります。修正後の赤字が、逆行列のコードです。これをアイマックスに書き換えていきます。
• 逆行列計算をアイマックスに書き換える際に、注意すべき点があります。これまでのプログラムは、データの横方向の長さが一定でした。しかし、LU分解を使うということは、三角行列を扱います。これは、横方向のデータの長さが、徐々に長くなったり、短くなったりすることを意味します。たとえば、横方向の長さが1ワードしかない場合、CPUで実行したほうが速いので、最初から最後まで、全部アイマックスに計算させるのは愚かです。そこで、このプログラムのように、まず、データ長を調べて、短い場合は、左のCPUのコード、長い場合は、右のアイマックスのコードを使うといった、工夫をします。前に言ったように、アイマックスのコードは、CPUでも動かすことができるので、このような、ハイブリッドプログラムのデバッグも難しくありません。
• 右側の一部を拡大しました。赤枠の中が、元のCPUコードです。条件文の中に、メモリのあたいを更新する計算が書いてあります。これに対応するアイマックスのコードが、下の赤字部分です。機械学習編の中で、普通のCGRAは、行列積を縦に計算しますが、アイマックスは、縦にも横にも計算できると言いました。後者は、ローカルメモリの内容を取り出して、加工し、書き戻す時に役立ちます。この赤字部分も、後者を利用して実装しています。赤字部分は、逆行列計算の1行分に対応し、同様の組を下にコピーすることで、複数ぎょうの処理を一度に行います。
• さらに拡大しました。条件文に相当する機能は、画像フィルタ上級編で説明しました。条件付き代入機能CMOVが、データを切り替えることができました。しかし、今回は、ストアするかどうかを切り替える必要があります。このためにアイマックスが備えているのが、条件付きストアです。まず、最初のぎょうの、CMP関数が、上位32ビット同士の比較結果と、下位32ビット同士の比較結果を、64ビットレジスタの、ビット32とビット0に格納します。次に、CEX関数が用意されています。3番目から6番目のパラメタに、CMP関数の結果を指定します。使わない部分は0にします。CEX関数は、4つのパラメタで指定された64ビットレジスタの、ビット32だけを並べて4ビットのあたいにし、7番目の16ビットパラメタと組み合わせて、ex0のうえ1ビットを生成します。同じように、４つのビット0を並べて4ビットのあたいにしたものから、ex0のした1ビットを生成します。あとは、4ビットの比較結果と、16ビットパラメタから、どうやってex0の1ビットを作るかを理解すればおわりです。下の図をみてください。4ビットの比較結果は、0000からいちいちいちいちまでの16通りあります。0000の場合にストアするかどうかを、16ビットパラメタのビット0に指定します。同様に、0001の場合にストアするかどうかを、16ビットパラメタのビット1に指定します。
こうして生成した、ex0を使って、最後のストアを制御します。今までと違って、最後のストア関数の2番目に、ex0というパラメタが増えています。うえ1ビットが、ストアデータの上位32ビットを本当にストアするかどうか、同様に、下1ビットが、下位32ビットをストアするかどうかを決めます。もうわかりましたね。複数のCMP関数で作った、合計4ビットの比較結果を使って、あらゆるパターンの条件付きストアを、上位32ビットと下位32ビット独立に、書くことができます。赤字の部分では、ビット0しか使っていないので、比較結果は、0000か0001の2通りしかありません。16ビットパラメタに、ここでは、aaaaと書いてありますが、0002でも同じ意味です。
• LU分解が終わったので、次は、前進消去です。こまかい説明は省略です。
• 最後の、後退代入です。
• ３つまとめて、コンパイル結果です。黒い部分が多いので、まだ高密度化できそうです。これは、みなさんへの宿題です。
• 今回は、逆行列を題材に、ローカルメモリ更新機能や、条件付きストアを説明しました。では、今回はここまでです。おつかれさま。