4.5 SPEにおけるスカラ演算
出典: PS3 Linux Information Site / Cell/B.E.のパワーを体験しよう
SPEはSIMD演算に最適化されたプロセッサですが、スカラ演算もおこなえます。ただし、その際には注意が必要です。ここでは、SPEにおけるスカラ演算の効率性と、スカラデータをSPEで扱う場合の注意事項について解説します。
4.5.1 プリファード・スカラ・エレメント
既存のアーキテクチャの多くでは、スカラデータ用とベクタデータ用にそれぞれ専用のレジスタが用意されています。しかし、SPEにはスカラデータ用の特別なレジスタは存在せず、ベクタデータを扱うレジスタと同じレジスタが使用されます。また、スカラデータ用のロード・ストア命令や演算命令はなく、スカラ演算はSIMD命令を用いて実現されます。
SPEでは、レジスタ全体ではなく特定の一部分だけに注目することによってスカラデータを扱います。このレジスタ内の決められた場所は、「プリファード・スカラ・エレメント」と呼ばれ、図 4.11のようにデータサイズごとに位置が決められています。
スカラデータのデータ型に応じて、char型はバイト3の位置に、short型はバイト2~3の位置に、int型やfloat型はバイト0~3の位置に、long long型やdouble型はバイト0~7の位置に、それぞれ配置する必要があります。また、スカラデータの他に、アドレスを示すポインタ型もバイト0~3の位置に配置しなければいけません。
例えば、SIMD命令を使ってスカラ演算の加算を計算するためには、図 4.12 (a) のようにレジスタ内のスカラデータの位置が揃っている必要があります。もし、レジスタ内でスカラデータの位置がずれていると、図 4.12 (b) のように正しい加算はおこなれません。
単純に計算をするだけであれば、スカラデータをどの位置に揃えて配置してもいいのですが、プリファード・スカラ・エレメントという特別な位置を決めて、そこを使うのには、いくつかの理由があります。
例えば、そのうちの1つは、SPEの命令セットの設計によるものです。SPEの命令セットでは、ロード・ストア命令におけるアドレス指定のようなスカラデータはプリファード・スカラ・エレメントに配置されることになっています。そのため、ロード・ストア命令で指定するアドレスを計算によって求めるような場合には、プリファード・スカラ・エレメントを使って計算すれば、計算結果をロード・ストア命令にそのまま渡せます。
4.5.2 スカラデータのロードとストア
ここでは、PPEとSPEにおけるスカラ演算を比較して、SPEにおけるスカラ演算の効率性について解説します。
PPEには、既存のアーキテクチャの多くと同様に、ベクタデータ用とスカラデータ用にそれぞれ別々のレジスタがあります。また、PPEでは、バイトやワードのような各種のデータサイズに応じたスカラデータのロードやストアができますので、スカラ演算は、図 4.13に示すように「ロード」-「計算」-「ストア」という単純な操作でできます。
一方、SPEでは、前節で述べたように、スカラ演算もすべてSIMD命令を利用して実現され、その際にはプリファード・スカラ・エレメントにスカラデータを配置する必要があります。しかし、第4.4節で説明したように16バイト境界から16バイト単位でのロードやストアしかできないため、SPEにおけるスカラ演算は、PPEにおけるスカラ演算のような単純な操作にはなりません。SPEにおけるスカラ演算の流れを図 4.14に示します。
SPEでは、まず入力のスカラデータを含む16バイトのデータをロードし、レジスタ上の適切なプリファード・スカラ・エレメントへシフトして、計算します。また、計算結果をストアする際は、スカラデータのみを直接ストアすることはできないので、ストア先を含む16バイトのデータをロードし、その一部分だけを計算結果で置き換えたものをストアします。
このように、SPEにおけるロード・ストアを伴うスカラ演算はPPEと比較すると効率的ではありません。例えば、以下のようなコードではスカラデータのロードやストアが頻繁に発生し、プログラム全体の性能に大きく影響するため、特に注意が必要です。
(1) スカラ配列の要素に対する参照
int a[16], b[16]; a[i] = b[i]++;
(2) スカラデータへのポインタを介した参照
int *a, *b; *(a + i) = *(b + i)++;
(3) 構造体のメンバ変数の参照
struct foo bar; b = bar.a + 1;
ただし、メモリ上に格納されないデータを利用するスカラ演算では、ロードやストアの操作が不要なため性能低下は起こりません。例えば、for文のカウンタ変数のインクリメントなどは通常レジスタのみで演算されるので、スカラ演算による計算でも問題はありません。
4.5.3 スカラ用SIMD組み込み関数
第2章の解答プログラム (2-1) の最後で、部分和の合計値を求める時のように、ベクタデータの各要素に対して操作をしたいことがあります。このような目的のために、SPEでは、スカラデータとベクタデータの変換用に3つの組み込み関数が提供されています。必要に応じて、これらの組み込み関数を活用することで、効率的なSPEプログラミングができます。表 4.5にスカラ用SPU組み込み関数一覧を示します。
| 関数名 | 説明 |
|---|---|
| d = spu_promote(a, element) | スカラaの値をelement番目の要素に含む新たなベクタデータを生成し、ベクタdに代入します。 |
| spu_insert(a, b, element) | スカラaの値をベクタbのelement番目の要素に挿入します。 |
| d = spu_extract(a, element) | ベクタaのelement番目の値をスカラdに代入します。 |
| d = spu_splats(a) | スカラaの値をすべての要素に展開した新たなベクタデータを生成し、ベクタdに代入します。 |
| d = spu_gather(a) | ベクタaの各要素の最下位ビットの値を抜き出し結合したビット列を0番目のワード要素に格納したベクタデータを生成し、ベクタdに代入します。 |
これらの組み込み関数についてさらに詳しく学習したい方は、「C/C++ Language Extensions for Cell Broadband Engined Architecture」の第2.13節「Scalar Intrincis」を参照してください。




