在对c ++中的整数数组进行线性搜索时,SSE比较不能正常工作

时间:2016-06-25 22:40:15

标签: c++ sse linear-search

我有以下代码用于在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();
}

它有效,但main函数中的示例应返回false,因为128不在example_array中,但sse2_search_array似乎总是返回true,并且示例中的result的值是1110111011101110b或61166,这对我没有意义,因为我期待它为0.所以有人可以告诉我问题是什么以及如何解决它?我对c ++不是很熟悉,对SSE知之甚少。

1 个答案:

答案 0 :(得分:3)

两个主要问题:

永远不要填充临时数组,以便将其作为向量加载:

__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是4个字节(在所有现代x86编译器上),但您显然希望使用单字节元素数组,因为您正在使用_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。也许你的意思是&#34;字节&#34;?

如果您确实想要搜索int的数组,请使用_mm_set1_epi32(key)_mm_cmpeq_epi32。 16字节向量包含四个int s。 movemask结果仍然基于字节,但结果中每组4位都是相同的。

另请参阅代码Wiki和代码wiki以获取有用的链接。 标签wiki在语言方面有很多好东西,因为你说你也是新手。

IDK为什么你获得了关键= 128的命中率;这似乎没有意义,除非你的代码更加错误,我没有注意到。

您的调试器应该能够向您展示__m128i变量中的内容。在变量中存储一些临时值将使用C ++源代码级调试器更容易查看它们,而不是单步执行asm代码。