Top: 6 lines / tails
Par: 15 lines
\(Y[i, j] = X[i, I[i, j]]\) を計算してください。
[0.1, 1.1, 2.1, ..., 1023.1]
が格納されています。補足:厳密には、\(0.1\) は表現不可能なので、これに一番近い倍精度浮動小数点数が格納されています。
PE 単体で問題を考えると、 \(1\) 次元配列 \(X\), \(I\) に対し、\(Y[j] = X[I[j]]\) を計算してくださいという問題になります。詳しくは Inputs をご覧ください。
変数 \(x\) の値に応じて配列 \(A\) の中から特定の場所の値を得る操作である間接参照 \(A[x]\) は、プログラミングを行う上では馴染み深いでしょう。
MN-Core では T レジスタを用いることで、LM0 の固定ではない、自由なアドレスにアクセスすることができます(T レジスタ間接参照。SDM 3.6.1.6「LM0」)。
T レジスタ(SDM 3.6.1.12「T レジスタ」)は PE あたりの容量が \(8\) 長語の、非常に小さいレジスタです。アドレス指定は無く、サイクルごとに独立した \(2\) 長語領域へ自動的に切り替わり、$t
, $lt
, $llt
で GRF や LM と同様に入出力できます。常に \(2\) 長語でアクセスされるので、先の \(3\) つの表記はすべて $llt
と同じ扱いになります。
さて、間接参照では、LM0 へのアクセスで $lm0v
のように書いていたところを $lmt0v
のように t
を付け加えます。
そうすると \(1\) ステップ内の各サイクルで T レジスタから読み出された整数値ぶん、アクセスするアドレス値に加算されます。
このとき、単語 $mt0v
、長語 $lmt0v
、二長語 $llmt0v
などの語長指定に関わらず、T レジスタからはサイクルごとに対応した単一の長語が読み出されます。
以下の VSM をご覧ください。
$subpeid
とは、各 PE の PE 番号を得られる、\(0\)~\(3\) の整数値です(SDM 3.6.1.20「固定値入力オペランド」)。
もし $m100v
と指定した場合、全ての PE が \(4\) サイクルかけて $m[100,101,102,103]
へアクセスします。
$mt100v
のように T レジスタ間接参照を用いると、このプログラムでは T レジスタに PE 番号を書いているので、PE0 は $m[100,101,102,103]
へ、PE3 は $m[103,104,105,106]
へ、というように、PE 番号の分だけずれた場所にアクセスされます。
自動インクリメントが必要なければ、$mt100
と指定することで、アドレス \(100\) を基準に、毎サイクルの T レジスタの内容を元にアクセス先が決定されます。
T レジスタの値が先程の例と一緒であれば、PE0 は $m[100,100,100,100]
へ、PE3 は $m[103,103,103,103]
へアクセスされます。
なお、$lmt100v
のような長語アクセスを行いたい場合、アドレス値は単語基準であり、長語のアドレスは \(2\) の倍数しか許されないため、端数は切り捨てられます。
また T レジスタへの代入時に、lpassa $n0v $t
のように入力として単語を指定した場合、T レジスタに関しては $t
と記述しても $lt
と記述しても \(2\) 長語アクセスとなるため、単語で読み込んだ \(32\) bit 値が先頭に詰められて残りが \(0\) 埋めされたものが、T レジスタに書き込まれます。
そのため、T レジスタを長語で読み出したとき、\(64\) bit の長語範囲のうち末尾 \(32\) bit は \(0\) になり、間接参照のために読み出すアドレス値が \(0\) 扱いになるのでお気をつけください。
ipassa $ln0v $t
であれば、長語で読み込んだ値を(単語単位で転送演算したのち)T レジスタに書き込むので問題ありません。
$subpeid
のような固定値入力も \(2\) 長語分を並べたものが入力されるため問題ありません。
A[i, j]
のような間接参照は、特にループと組み合わせて配列の \(i\) 行 \(j\) 列目の要素を取得する操作として頻出です。
それにもかかわらず MN-Core の間接参照は、一旦 T レジスタに値を入れ、T レジスタの書き込み完了に \(1\) ステップ待った上で、LM0 にアクセスしないといけません。
また、LM1 や GRF0/1 など、他のレジスタは間接参照に対応していません。
このように、お世辞にも便利とは言えない MN-Core の間接参照ですが、MN-Core の主な計算ターゲットではコンパイル時にループ量などが既知であり、またコンパイル時にループアンロールも行われるため、基本的にコンパイル時にアクセスするアドレスが決定されます。
したがって、MN-Core の主なワークロードでは間接参照が必要になることが少ないため、このような最低限の設計になっています。
$lm[0:2048]
/ ((16_MAB:1), (1024:1); B@[PE,L1B,L2B])
$lm[2048:2080]
/ ((16_MAB:1), (16:1); B@[PE,L1B,L2B])
$ln[0:32]
/ ((16_MAB:1), (16:1))