機能

C++ SIMDの各クラスには、次のような基本的な機能があります。

目的の結果を得るためには、これら諸機能についてそれぞれ理解し、これら諸機能が互いにどのように作用し合うのかを理解することが重要です。

計算

SIMD C++ の各クラスは、シフトや飽和をはじめとしてほとんどの算術演算用の垂直演算子に対応しています。

算術演算には、+-*/、逆数(rcprcp_nr)、平方根(sqrt)、平方根の逆数(rsqrtrsqrt_nr)があります。

rcpおよびrsqrtという演算は、非常に短いレイテンシで近似値の計算ができる新しい命令のことで、最低でも12ビットの精度を持つ計算結果が得られます。rcp_nrおよびrsqrt_nrという演算は、ソフトウェア的にいくつか改良がなされていて、パフォーマンスにはごく小さい影響しか与えずに精度の高い近似値が得られます。「nr」は、近似値を使ってパフォーマンスを改善する数学的手法の1つである「Newton-Raphson法」の頭文字です。

水平データのサポート

C++ SIMDの各クラスは、一部の算術演算については水平処理もできます。「水平」とは、1個のベクトルに含まれているすべての要素について、横方向に端から端まで計算することを指します。 一方「垂直」とは、2個の異なるベクトルについて、縦方向に要素単位で計算していくことを指します。

例えばadd_horizontalunpack_lowpack_satという各関数は、水平データに対応しています。このように水平データに対応していると、SIMD命令の能力をすべては利用できない一部のアルゴリズムも使用できるようになります。

シャッフル組込み関数も水平データフローのもう1つの例です。シャッフル組込み関数は、即値引数を使用するため、C++ の各クラスの中には示されていません。ただし、C++ SIMD クラスでは、シャッフル組込み関数を他の C++ 関数と混在できます。次に例を示します。

F32vec4 fveca, fvecb, fvecd;
fveca += fvecb;
fvecd = _mm_shuffle_ps(fveca,fvecb,0);

一般に、水平データフローを用いると、どの命令の場合も、実装に際しては少し無駄な部分ができます。できる限り、アルゴリズムを実装するときは水平機能は使用しないでください。

分岐の圧縮/削除

SIMD アーキテクチャでの分岐処理は、複雑で手間がかかることがあり、場合によっては分岐予測の精度が下がったり、コードのサイズが増えたりします。SIMD C++ クラスには、論理演算、最大値/最小値関数、条件付き選択、比較を使うことによって分岐をなくすための関数がいくつか用意されています。次の例について考えてみます。

short a[4], b[4], c[4];
for (i=0; i<4; i++)
c[i] = a[i] > b[i] ? a[i] :b[i];

この演算はiの値とは無関係です。iの値が変わるごとに、その結果は、実際の値に応じてABのいずれかになります。分岐を完全になくす簡単な方法の1つは、次のようにselect_gt関数を使うことです。

Is16vec4 a, b, c
c = select_gt(a, b, a, b)

キャッシング・ヒント

ストリーミングSIMD拡張命令には、プリフェッチとストリーミング・ヒントという機能があります。データをプリフェッチすると、メモリ・レイテンシの影響を最小限に抑えられます。ストリーミング・ヒントを使用すると、キャッシュしないほうが望ましいデータを示すことができます。これにより、キャッシュしたほうが望ましいデータのパフォーマンスが上がります。