6

開始位置と終了位置を示す2つの符号なしショートのコンパクトな構造体を使用しています。しきい値を超える長さ(開始から終了までの差)を持つオブジェクト
があるかどうかをすばやく判断できる必要があります。Range

それぞれが独自の配列を持つ膨大な量のオブジェクトを作成するため、リストなどでしきい値を超えているオブジェクトRangeを追跡することはできません。Rangeこのコードも非常に頻繁に実行されるため(配列ごとに1秒間に何回も)、効率的である必要があります。

struct Range
{
 unsigned short start;
 unsigned short end;
}

私は常にRangeサイズ2^nの配列を持っています。しきい値を超えるものが見つかったらすぐに中止したいのですが、ループをベクトル化できると仮定すると、単純にORをとって、最後にチェックする方が速いと確信しています。各ベクトルの結果のチャンクに対してifステートメントを実行できれば、それは素晴らしいことです。

size_t rangecount = 1 << resolution;
Range* ranges = new Range[rangecount];

...

bool result = false;
for (size_t i = 0; i < ranges; ++i)
{
 result |= (range[i].end - range[i].start) > 4;
}

当然のことながら、私のデータ型は32ビットまたは64ビット幅ではないため、自動ベクトル化機能によって1202エラーが発生します。データサイズを2倍にして、各フィールドをunsignedintにしたくありません。だから私は自動ベクトル化のアプローチがこれのために出ていると思います。

16ビット変数を処理できるベクトル命令はありますか?ある場合、ループをベクトル化するためにC ++でそれらをどのように使用できますか?

4

1 に答える 1

1

4より大きい値があるかどうか疑問に思っていますか?

はい、これにはSIMDの説明があります。自動ベクトル化がこのシナリオを処理できないのは残念です。ベクトル化されたアルゴリズムは次のとおりです。

diff_v = end_v - start_v; // _mm_hsub_epi16 
floor_v = max(4_v, diff_v); // _mm_max_epi16 
if (floor_v != 4_v) return true; // wide scalar comparison

_mm_sub_epi16配列の構造体または構造体の配列で使用します_mm_hsub_epi16

実際startには、最初にメモリに格納されるため、作業を行うことになります。したがって、とのベクトルをstart_v - end_v使用します。_mm_min_epi16-4

各SSE3命令は、一度に8つの比較を実行します。ループするのではなく、早めに戻るのが依然として最速です。ただし、ループをもう少し展開すると、速度が向上する可能性があります(最初の結果セットをパックされた最小/最大関数に渡してそれらを結合します)。

したがって、最終的には(おおよそ):

most_negative = threshold = _mm_set_epi64(0xFCFCFCFCFCFCFCFC); // vectorized -4

loop:
    a = load from range;
    b = load from range;
    diff = _mm_hsub_epi16(a, b);
    most_negative = _mm_min_epi16(most_negative, diff);

    // unroll by repeating the above four instructions 4 times or so
    if (most_negative != threshold) return true;
repeat loop
于 2012-12-21T16:23:15.437 に答える