2.2 SIMDプログラミングで扱うデータ
出典: PS3 Linux Information Site / Cell/B.E.のパワーを体験しよう
ここでは、SIMDプログラミングで扱われるデータについて解説します。
2.2.1 ベクタ型
従来のCプログラミングで使用する「char」「int」「float」などのデータ型をスカラ型といいます。一方、SIMD演算で扱うデータ型をベクタ型といいます。ベクタ型には、表 2.2のようにスカラ型それぞれに対応した型があります。また、それらの型で表されるデータのことを「スカラデータ」「ベクタデータ」といいます。
| ベクタ型 | 内容 |
|---|---|
| vector unsigned char | 16個の符号なし8ビットデータ |
| vector signed char | 16個の符号付き8ビットデータ |
| vector unsigned short | 8個の符号なし16ビットデータ |
| vector signed short | 8個の符号付き16ビットデータ |
| vector unsigned int | 4個の符号なし32ビットデータ |
| vector signed int | 4個の符号付き32ビットデータ |
| vector unsigned long long | 2個の符号なし64ビットデータ |
| vector signed long long | 2個の符号付き64ビットデータ |
| vector float | 4個の単精度浮動小数点データ |
| vector double | 2個の倍精度浮動小数点データ |
2.2.2 ベクタデータの配置 (バイトオーダ)
Cellで扱うベクタデータは、すべて128ビット (=16バイト) 固定長で、データ型によって2から16個の要素を含みます。16バイト長の配列に「char」や「int」のスカラデータがひと固まりに格納されたものと考えられます。図 2.4に示すように、Cellでは、バイトオーダ(*)、要素番号はビッグエンディアンで扱われます。
![]() |
- バイトオーダ … コンピュータが2バイト以上のデータをメモリ上に記録する際のバイトの並べ方。最上位バイト (MSB) から順番に記録する方式を「ビッグエンディアン」、最下位バイト (LSB) から順番に記録する方式を「リトルエンディアン」といいます。例えば、「0x12345678」という4バイトのデータは、ビッグエンディアンでは「0x12」「0x34」「0x56」「0x78」という順番で、リトルエンディアンでは「0x78」「0x56」「0x34」「0x12」という順番で記録されます。
2.2.3 ベクタリテラル
ベクタリテラル (直定数) は、小括弧 ( ) で括られたベクタ型と中括弧 { } で括られた一組の定数式で記述されます。ベクタの要素は対応する定数式を用いて初期化されます。対応する式が指定されない要素はデフォルト値0が適用されます。ベクタリテラルは、初期化文の中であるいは実行文の定数として使用できます。以下に、ベクタリテラルの使用例を示します。
用例 (2-1) 変数の初期化文で使用する (赤字:ベクタリテラル)
void func_a(void)
{
vector signed int va = (vector signed int) { -2, -1, 1, 2 };
用例 (2-2) 実行文の定数として使用する (赤字:ベクタリテラル)
va = vec_add(va, ((vector signed int) { 1, 2, 3, 4 }));
なお、ベクタリテラルをマクロに使用する場合、ベクタリテラル全体を小括弧 ( ) で括る必要があります。表 2.3にベクタリテラル一覧を示します。
| リテラル表記 | 意味 |
|---|---|
| ( vector unsigned char ) { unsigned int, … } | 16個の符号なし8ビットデータ1セット |
| ( vector signed char ) { signed int, … } | 16個の符号付き8ビットデータ1セット |
| ( vector unsigned short ) { unsigned short, … } | 8個の符号なし16ビットデータ1セット |
| ( vector signed short ) { signed int, … } | 8個の符号付き16ビットデータ1セット |
| ( vector unsigned int ) { unsigned int, … } | 4個の符号なし32ビットデータ1セット |
| ( vector signed int ) { signed int, … } | 4個の符号付き32ビットデータ1セット |
| ( vector unsigned long long ) { unsigned long long, … } | 2個の符号なし64ビットデータ1セット |
| ( vector signed long long ) { signed long long, … } | 2個の符号付き64ビットデータ1セット |
| ( vector float ) { float, … } | 4個の32ビット浮動小数点データ1セット |
| ( vector double ) { double, … } | 2個の64ビット浮動小数点データ1セット |
2.2.4 ベクタデータとスカラデータの関係
SIMDプログラミングでは、ベクタデータの各要素をスカラデータとして参照したい場合や、複数のスカラデータを1つのベクタデータとして参照したい場合があります。例えば、ベクタデータの3番目の要素を出力する場合や、スカラ配列の入力データをベクタデータにまとめてSIMD演算で処理する場合です。ここでは、そのような参照の方法について説明します。
図 2.4のベクタデータの配置図を思い出してください。ベクタデータは、16バイト長のスカラ配列と同じデータ構造をしています。図2.5は、実際のメモリ上のデータの配置を表現しています。このように、1つのベクタデータ (図 2.5 (a)) は、16バイト長のスカラ配列 (図 2.5 (b)) として見ることができます。
![]() |
このデータの見方の変更は、C言語で表現すると、ポインタのキャストに相当します。ベクタデータが格納されたアドレスを指すポインタを、スカラ型のポインタでキャストすることで、スカラデータとして参照できます。具体例として、ベクタデータをスカラ配列として参照する方法を以下に示します。
用例 (2-3) ベクタデータの第3要素をスカラデータとして参照する (赤字:ポインタのキャスト)
vector signed int va = (vector signed int) { 1, 2, 3, 4 };
int *a = (int *) &va;
printf(“a[2] = %d\n”, a[2]);
同じようにメモリ上でのデータの見方を変えることで、スカラ配列をベクタデータとして参照することもできます。具体的には、用例 (2-4) のように、スカラ配列の先頭アドレスを指すポインタを、ベクタ型のポインタへキャストすることで、ベクタデータとして扱えるようになります。
用例 (2-4) スカラ配列をベクタデータとして参照する (赤字:ポインタのキャスト)
int a[8] __attribute__((aligned(16))) = { 1, 2, 3, 4, 5, 6, 7, 8 };
vector signed int *va = (vector signed int *) a;
/* va[0] = { 1, 2, 3, 4}, va[1] = { 5, 6, 7, 8 } */
vb = vec_add(va[0], va[1]);
なお、スカラデータをベクタデータとしてポインタで参照する場合、図 2.6のようにスカラデータのアドレスを16バイト境界 (下位4ビットがすべて0のアドレス) に揃えておく必要があります。16バイト境界に揃えられていないスカラデータは、ベクタデータとして期待したとおりに参照できない場合があります。
![]() |
用例 (2-4)では、キーワード__attribute__を用いて、スカラ配列aにaligned属性が指定されています。aligned属性は、データをメモリ上のバイト境界に揃えて格納するための属性です。
詳細については、第4章で解説します。ここでは、スカラデータをベクタデータとして参照する場合は、データを16バイト境界に揃えて格納する必要があることを覚えておいてください。



