1

C++ でストリーミング SIMD 拡張機能を使用して、配列を介して線形検索を実行することを目的とした次のコードがあります。

#include <iostream>
#include <emmintrin.h>

using namespace std;

bool sse2_search_array(int* arr, int size, int key) {
    int iterations;
    if (size % 16 == 0) {
        iterations = size / 16;
    }
    else {
        iterations = size / 16 + 1;
    }
    __m128i* arr_ = reinterpret_cast<__m128i*>(arr);  /*Cast to corresponding int type for 128 bit registers. Each __m128i
                                occupies 8 bits, so 16 integers can be processed simultaneously.*/
    __declspec(align(16)) int key_arr[16];
    fill_n(key_arr, 16, key);  /*fill key array with 16 keys (for SSE comparisons)*/
    __m128i* key_arr_ = reinterpret_cast<__m128i*>(key_arr);

    int result;
    /*Actual search begins here.*/
    for (int i = 0; i < iterations; i++, arr_++) {
        result = _mm_movemask_epi8(_mm_cmpeq_epi8( *key_arr_, *arr_));  /*Comparison of 2 16 bit arrays simultaneously.*/
        cout << "result: " << result << endl;
        if (result != 0) { return true; }
    }
    return false;

}

int main() {
    __declspec(align(16)) int example_array[16] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6 };

    cout << "found: " << sse2_search_array(example_array, 16, 128);
    cin.get();
}

それは機能しますが、128 は にないため、メイン関数の例は false を返す必要がありますがexample_arraysse2_search_array常に true を返すように見えますresult。では、何が問題で、どうすれば修正できるか教えてもらえますか? 私は C++ の経験があまりなく、SSE についてもほとんど知りません。

4

1 に答える 1

3

2 つの大きな問題:

ベクトルとしてロードできるようにするためだけに、スクラッチ配列を埋めないでください。

__declspec(align(16)) int key_arr[16];
fill_n(key_arr, 16, key);  /*fill key array with 16 keys (for SSE comparisons)*/
__m128i* key_arr_ = reinterpret_cast<__m128i*>(key_arr);

代わりに、を使用して__m128i keyvec = _mm_set1_epi8(key);ください。ベクトルのすべての位置にバイトをブロードキャストする方法は、メモリに 16 個のスカラー ストアを実行してからベクトルをロードする (ストア フォワーディング ストールの影響を受ける) よりもはるかに高速です。_mm_setローカル配列に書き込む代わりに、組み込み関数を使用してコンパイラに選択させます。


int(最新のすべての x86 コンパイラで) は 4 バイトですが、_mm_cmpeq_epi8. あなたexample_arrayは実際には16 * 4バイトの長さです:

__declspec(align(16)) int example_array[16] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6 };
// equivalent byte array (on little-endian x86):
uint8_t byte_array[16*sizeof(int)] = { 1,0,0,0,  2,0,0,0,  3,0,0,0, ... };

あなたのコメントはしばしば完全に間違っていComparison of 2 16 bit arrays simultaneouslyます。もしかして「バイト」のことですか?


実際に の配列を検索したい場合は、 とintを使用_mm_set1_epi32(key)_mm_cmpeq_epi32ます。16 バイトのベクトルは 4 つintの を保持します。movemask の結果は引き続きバイトに基づいていますが、結果の 4 ビットの各グループは同じになります。

便利なリンクについては、 タグ wiki とタグ wikiも参照してください。あなたもそれが初めてだと言ったので、c ++タグwikiには、一般的に言語に関する多くの優れたものがあります


key=128; のヒットを取得している IDK の理由。私が気付かなかったコードにさらに問題がない限り、それは意味がないようです。

__m128iデバッガーは、変数の内容を表示できるはずです。一部の一時変数を変数に格納すると、asm コードをシングルステップ実行する代わりに、C++ ソースレベル デバッガーでそれらを簡単に確認できるようになります。

于 2016-06-25T23:20:17.047 に答える