はじめに
NEC SX-Aurora TSUBASAのnc++にてベクトル命令のIntrinsicが解禁されたということで、早速使ってみるテスト。
とはいえ、マニュアル等もほとんどないので、教えてもらった情報や、webサーフィンしながら集めた情報を組み合わせて、なんとか動くところまで持っていきます。
※NECさんより正確な情報を頂くことができたので、一部を修正しました。ただし、当時の試行錯誤も自身にとっての記録として重要なので、最低限の修正に留めました。
必要な環境
コンパイラ ver 4.0.0以降が必要です。
コードはどう書くのか
webで現状でみつかる_vel_~~
で始まる命令は使えません。コンパイラ4.0.0以降では、__builtin_ve_~~
で始まる命令になっています。
参考1:https://sx-aurora-dev.github.io/ve-intrinsics-tutorial/
追記: 読める環境にいる方は、NEC C++マニュアルのver.4.0.0以降からはi
ntrinsicに関する情報が少し載っています。
また、Intrinsic用に何かヘッダーをインクルードする必要もありません(少なくとも今試している限りでは)。何もインクルードすることなく__builtin_ve_~~
命令を書いてしまってコンパイルは通ります。
どんな命令があるのかは、コンパイラのインストールされたディレクトリのinclude/_vector.h
の中に書いてあります。(注意点として、このヘッダーをインクルードしてはいけません。コンパイルが通りません。)
サンプルプログラム
先にサンプルコードを載せた方がイメージしやすいと思うので、簡単な例を載せます。
#include <cstdio>
//the definition of vector type. 2048 means 8 byte x 256 //
typedef double __vr __attribute__((__vector_size__(2048)));
int main(){
constexpr int n = 256;
double b[n]={0.0};
for (int i = 0; i < n; ++i) {
b[i] = (double)i;
}
//definition of vector type variable a//
__vr a;
//load to vector type a from double array b//
__builtin_ve_vld(a, b, 8);
// clear b
for (int i = 0; i < n; ++i) {
b[i] = 0.0;
}
//set from vector type a to double array b//
__builtin_ve_vst(a, b, 8);
//if the vector opeartion is correctly used, the numbers from 0.0 to 255.0 are printed.//
for (int i = 0; i < n; ++i) {
printf("b[%d] = %f\n", i, b[i]);
}
return 0;
}
これは、ベクトル型の変数aに、配列bから値をセットして、またaからbへ書き戻すだけのプログラムです。無事に書き戻せたことが分かるように、書き戻す前にbを0クリアしています。成功すれば0.0から255.0の値が表示されます。
ベクトル変数の定義
ベクトル演算ではベクトル型の変数を用います。まずはベクトル型自体を次のように定義します
//the definition of vector type. 2048 means 8 byte x 256 //
typedef double __vr __attribute__((__vector_size__(2048)));
サイズはバイト単位で指定するようで、8tyte×256=2048byteとなります。これ以外の大きさの方が使えるかは不明です。
追記: __attribute__((__vector_size__(数字)))
での指定では2のべき乗数の指定が可能です。また、__attribute__((ext_vector_type(数字)))
で指定することもでき、こちらは任意の数を指定できるようです(とはいえ256以下と思われる)。
実際にベクトル型の変数を確保するには、次のように定義します。
//definition of vector type variable a//
__vr a;
ベクトル変数への値の代入
事前に配列bに値を入れておいて、そこからベクトル型の変数へ代入(load)します。次の部分です。
//load to vector type a from double array b//
__builtin_ve_vld(a, b, 8);
第三引数の8はストライドですが、いろいろ試してこの値が上手くいきました。経験則です。
ベクトル変数からの値の読み取り
今度はベクトル変数aから配列bに値を書き戻します(set)。次の部分です。
//set from vector type a to double array b//
__builtin_ve_vst(a, b, 8);
ここでも第三引数のストライドを8にしました。
コンパイル
まずはコンパイラの4.0.0を有効化します。私の環境では次のようにします。
module load NECSDK-sx/4.0.0
あとは特に何も考えず、コンパイルします。ソースファイルをtest.cpp
としたとき、次のようにします。
nc++ test.cpp
おわりに
webで出回っている命令と違っていたので、最初は何かインクルードしなきゃとか、velintrin.hが見つからないとかかなり混乱しましたが、なんとか動くところまで来ました。webの情報とは違ってclangも使わないようです。
**追記:**clangは使わないとオフィシャルな回答を頂きました。
徐々に慣れていけそうです。
これでコンパイラとエスパー対決しなくてよくなると思うと、かなり気が楽になります。
メリークリスマス!