前回までで、IntelからOpenPOWERやRISC-VにIntrinsic関数をポートする方法について議論してきた。
ポートには、以下のようなラッパー構造でIntelのIntrinsic関数を置換してやる。
extern __inline __m128d __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_cmpeq_sd(__m128d __A, __m128d __B)
{
__v2df __a, __b, __c;
/* PowerISA VSX does not allow partial (for just lower double)
results. So to insure we don't generate spurious exceptions
(from the upper double values) we splat the lower double
before we do the operation. */
__a = vec_splats (__A[0]);
__b = vec_splats (__B[0]);
__c = (__v2df) vec_cmpeq(__a, __b);
/* Then we merge the lower double result with the original upper
double from __A. */
return (__m128d) _mm_setr_pd (__c[0], __A[1]);
}
ここで湧き上がってくる疑問がある、このポートしたラッパー構造は本当に正しいのだろうか。
そこで必要なのは、__A
と__B
にランダムに生成した値を入力してやり、それをIntelとOpenPOWER側に入れてやって、帰ってくる値が同じであることを確認することである。
そこで必要なのは、__A
と__B
と、帰ってきた値をセットにして、ファイルに保存することである。
ファイルに保存するフォーマットとしては、XMLかJSONが良いと思う。では、保存するファイルフォーマットを記述していこう。toukaはテストフレームワーク燈花の名前である。等価をかけている。
<touka>
<head><version>1.00</version></head>
<body>
<IO><input><__A>(__Aの値をテキストに変換したもの)</__A><__B>(__Bの値をテキストに変換したもの)</__B></input>
<output>(帰ってきた値をテキストに変換したもの)</output></IO>
<IO><input><__A>(__Aの値をテキストに変換したもの)</__A><__B>(__Bの値をテキストに変換したもの)</__B></input>
<output>(帰ってきた値をテキストに変換したもの)</output></IO>
(テストの回数繰り返す)
<body>
</touka>
同じものをJSONで書いてみる。
{"touka":{"head":{"version":1.00},
"body":
{"IO":{"input":{"__A":"FAFAFAFAFAFAFAFAFAFAFAFAFAFAFAFA","__B":"FAFAFAFAFAFAFAFAFAFAFAFAFAFAFAFA"},"output":{"return":"FAFAFAFAFAFAFAFAFAFAFAFAFAFAFAFA"}}},
"IO":{"input":{"__A":"FAFAFAFAFAFAFAFAFAFAFAFAFAFAFAFA","__B":"FAFAFAFAFAFAFAFAFAFAFAFAFAFAFAFA"},"output":{"return":"FAFAFAFAFAFAFAFAFAFAFAFAFAFAFAFA"}}}}
この<IO>
タグのついた部分が、テストされた分入っている。
このJSONファイルをIntel側で生成して、ファイル転送によりOpenPOWERまたは、RISC-Vに移動し、ポートされたソースコードが正しいことを確認する。
値をテキストに変えるフォーマットについて議論をする必要がある。
JSONの作成またはパースをJavaで行い、それをC言語で作ったSIMD部に送信する手があるが、インターフェースを考えないといけない。
Java Native Interfaceを使う手がある。それについて考えていこうと思う。
Java部で、一回のIntrinsic関数実行分のデータを小分けにしてStringにしてSIMD部に送って、SIMD部でC言語の型にすることができる。
なので、C言語で、「C言語の型↔String」の変換モジュールを制作する必要がある。
Stringは__m128d
単体のものでよく、伝達したり小分けにするのはJava部の役割である。
その場合、__m128d
はIntel x86-64用のSIMD型であるため、それをOpenPOWERまたはRISC-Vにポートしたものにも対応する必要がある。
例えば、__m128d
単体をシリアライズする方法にはunionを使った以下のようなものがある。調査には生成AIを使った。このコードがRISC-VおよびOpenPOWERでも正常に動くか確認しないといけない。
次回から、__m128d
のシリアライズとデシリアライズについて議論していこうかと思う。
typedef union {
__m128d v;
double d[2];
} m128d_union;
void serialize_m128d(__m128d v, char *buf, size_t bufsize) {
m128d_union u;
u.v = v;
snprintf(buf, bufsize, "[%f, %f]", u.d[0], u.d[1]);
}