本サイトは、マルチコア トータルソリューションカンパニー -フィックスターズの技術者有志が運営するサイトです。

2.3 簡単なSIMD演算

出典: PS3 Linux Information Site / Cell/B.E.のパワーを体験しよう

 ここでは、加算の例題を用いてSIMD演算による簡単な四則演算について解説します。スカラ演算とSIMD演算を比較しながら、演算の効率とデータの扱い方を中心に解説します。

2.3.1 加算処理をおこなうプログラム

 ここでは4個の加算処理の結果を求めるプログラムを例に考えます。まず、リスト (2-1) に従来のプログラミングであるスカラ演算による加算処理プログラムを示します。

リスト (2-1) スカラ演算による加算処理

 1 int a[4] = { 1, 3, 5, 7 };
 2 int b[4] = { 2, 4, 6, 8 };
 3 int c[4];
 4
 5 c[0] = a[0] + b[0];     // 1 + 2
 6 c[1] = a[1] + b[1];     // 3 + 4
 7 c[2] = a[2] + b[2];     // 5 + 6
 8 c[3] = a[3] + b[3];     // 7 + 8

 スカラ演算では「単一データ = 単一データ + 単一データ」の構成で演算をおこないます。そのため、4個の加算結果を求めるためには、リスト (2-1) の5行目~8行目に示すように4回の加算命令を逐次的に実行する必要があります。

 次に、SIMD演算における加算処理プログラムを示します。

リスト (2-2) SIMD演算による加算処理

 1 int a[4] __attribute__((aligned(16))) = { 1, 3, 5, 7 };
 2 int b[4] __attribute__((aligned(16))) = { 2, 4, 6, 8 };
 3 int c[4] __attribute__((aligned(16)));
 4
 5 vector signed int *va = (vector signed int *) a;
 6 vector signed int *vb = (vector signed int *) b;
 7 vector signed int *vc = (vector signed int *) c;
 8
 9 *vc = vec_add(*va, *vb);    // 1 + 2, 3 + 4, 5 + 6, 7 + 8

 VMXでは、各SIMD命令に対応した組み込み関数が用意されています。リスト (2-2) の9行目で利用されているvec_add()関数は、VMXの加算命令に相当する組み込み関数です。

 SIMD演算では、「複数データ = 複数データ + 複数データ」の処理をおこないます。SIMD演算は1命令で演算できるデータ数がスカラ演算に比べて多く、演算結果を求めるための命令数を抑えることができるため、処理時間の短縮効果があります。

 第2.2節で述べたとおり、変数abcはベクタデータとして参照されるため、キーワード__attribute__を用いて16バイト境界に揃えられるようにaligned属性が指定されています。

2.3.2 例題プログラムの解説

 それでは、例題プログラムのソースコード全体について解説します。

例題プログラム (2-1) 加算処理プログラム全体

 1 #include <stdio.h>
 2 #include <altivec.h>
 3
 4 int a[4] __attribute__((aligned(16))) = { 1, 3, 5, 7 };
 5 int b[4] __attribute__((aligned(16))) = { 2, 4, 6, 8 };
 6 int c[4] __attribute__((aligned(16)));
 7
 8 int main(int argc, char **argv)
 9 {
10     vector signed int *va = (vector signed int *) a;
11     vector signed int *vb = (vector signed int *) b;
12     vector signed int *vc = (vector signed int *) c;
13
14     *vc = vec_add(*va, *vb);    // 1 + 2, 3 + 4, 5 + 6, 7 + 8
15
16     printf("c[0]=%d, c[1]=%d, c[2]=%d, c[3]=%d\n", c[0], c[1], c[2], c[3]);
17
18     return 0;
19 }

⇒例題プログラム (2-1) のソースコードはこちらから

2行目 VMXを使用する時に必要なヘッダファイル "altivec.h" をインクルードします。なお、VMX命令はAltiVecテクノロジを利用しているため、ヘッダファイルなどにAltiVecという文字列が含まれています。
4行目~6行目 入力される配列データabと合計値を格納するためのスカラ配列cを定義します。aligned属性で16バイト境界に変数のアドレスを揃えています。
10行目~12行目 SIMD演算に必要な変数を定義します。変数vavbvcは、SIMD演算で用いるベクタ変数へのポインタで、スカラ配列をベクタデータとして参照するために使用されます。
14行目 加算命令を実行するvec_add()関数を実行します。vec_add()関数は、vavbの対応した各要素を加算した結果を、vcの対応した要素に格納します。
16行目 計算結果を標準出力に表示します。

2.3.3 プログラムのコンパイルと実行

 プログラムのコンパイルは、gccコマンドを利用します。VMXを利用する場合は、コンパイルオプションとして、-maltivecオプションと-mabi=altivecオプションを指定します。

用例 (2-5) プログラムのコンパイル

$ gcc –maltivec –mabi=altivec vec_add.c –o vec_add.elf

 プログラムの実行は、従来のプログラムの実行方法と同じで、シェルプロンプト上でELF実行ファイルを指定して実行します。

用例 (2-6) プログラムの実行

$ ./vec_add.elf
c[0]=3, c[1]=7, c[2]=11, c[3]=15
$

2.3.4 VMX命令組込み関数 (Intrinsics)

 本節では、VMX加算命令に対応したvec_add()関数を紹介しました。加算命令以外の組込み関数についても、算術演算命令、ビット演算命令、比較演算命令など数多くのVMX命令に対応した組込み関数が提供されています。表 2.4に組込み関数の一例を示します。

表 2.4 VMX命令組込み関数 (一例)

種類関数名機能
算術演算命令 vec_add(a, b) ベクタabの各要素を加算します。
vec_sub(a, b) ベクタabの各要素を減算します。
vec_madd(a, b, c) ベクタabの各要素を乗算し、ベクタcの各要素を加算します。
vec_re(a) ベクタaの各要素の逆数を計算します。
vec_rsqrte(a) ベクタaの各要素の逆数平方根を計算します
論理演算命令 vec_and(a, b) ベクタabのビット毎の論理積を求めます。
vec_or(a, b) ベクタabのビット毎の論理和を求めます。
シフト・ローテート命令 vec_sr(a, b) ベクタaの各要素をベクタbの各要素で指定したビット数分だけ右シフトします。
vec_rl(a, b) ベクタaの各要素をベクタbの各要素で指定したビット数分だけ左ローテートします。
ビット演算命令 vec_perm(a, b, c) ベクタcで指定されたバイトパターンに基づいてベクタabの各要素を並べ替えます。
vec_sel(a, b, c) ベクタcで指定されたビットパターンに基づいてベクタabの各ビットを選択します。
比較分岐命令 vec_cmpeq(a, b) ベクタabの各要素が等しいか比較します。
vec_cmpgt(a, b) ベクタaの各要素がベクタbの各要素より大きいか比較します。
変換命令 vec_ctf(a, b) 整数ベクタaの各要素を2bで除算し、浮動小数点へ変換します。
vec_ctu(a, b) 浮動小数点ベクタaの各要素を2bで乗算し、符号なし整数へ変換します。
定数生成命令 vec_splat(a, b) ベクタab番目の要素を展開したベクタデータを生成します。
vec_splat_s32(a) スカラリテラルaを4個の符号付き32ビット量データに展開したベクタデータを生成します。

2.3.5 参考資料

 表 2.4に示した関数はVMX命令の代表的なものです。さらに詳しく学習したい方はFreescale Semiconductor社が公開している「AltiVec Technology Programing Interface Manual」の第4章を参照してください。



第2.2節」へ戻る 第2章目次 第2.4節」へ進む
チュートリアル目次
表示
個人用ツール
オープンソースプロジェクト
ツールボックス