0

SSEでのシフトがどのように機能するかを理解しようとしていますが、gdbの出力がわかりません。SSE4を使用すると、8つの16ビット符号なし整数を保持する128ビットベクトルがあります(を使用uint16_t)。次に、組み込み関数を使用し_mm_cmpgt_epi16てそれらをある値と比較します。この関数は、intを格納するために使用されるビットにすべての0または1ビットを入れます。これまでのところ、gdbを使用すると次のようになります。

(gdb) p/t sse_res[0]
$3 = {1111111111111111111111111111111111111111111111110000000000000000, 1111111111111111111111111111111111111111111111110000000000000000}

次に、それらを右にシフトしたいので(それは正しいですか?)、それが本当の場合に備えて、数値1を取得します。次に、GDBは私が理解できない出力を提供します。

(gdb) p/t shifted
$4 = {11101000000000010010000000000000110000000000000000011, 100111000000000001011000000000001001000000000000001111}

最初のものと同じ長さでもありません、なぜこれですか?試してみるために、次の組み込み関数を使用して1ビット右にシフトしました。

shifted = _mm_srli_epi16(sse_array[i], 1);

16ビットブロックごとに右端でゼロが1つだけシフトすることを期待していました。

アップデート:

私はビットマスクを使って物事をテストするための小さな例を書きました、それはうまくいきます、しかし私はまだgdbsの振る舞いを理解していません:

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>

#include <tmmintrin.h> 
#include <smmintrin.h>

void print128_num(__m128i vector)
{
    uint16_t *values = (uint16_t*) &vector;
    printf("Numerical: %i %i %i %i %i %i %i %i \n", 
           values[0], values[1], values[2], values[3], values[4], values[5], 
           values[6], values[7]);
}

int main (int argc, char **argv)
{
    uint16_t nums[] = {1, 57, 33, 22, 88, 99, 9, 73};

    __m128i *nums_sse = (__m128i*)(&nums);
    print128_num(*nums_sse);

    // vector of 42
    __m128i mm42 = _mm_set1_epi16(42);

    __m128i sse_res = _mm_cmpgt_epi16(*nums_sse, mm42);
    printf("Result of the comparison\n");
    print128_num(sse_res);

    // bitmask
    __m128i mask = _mm_set1_epi16(1);

    __m128i finally = _mm_and_si128(sse_res, mask);
    printf("Result of the masking\n");
    print128_num(finally);

    uint16_t* sse_ptr = (uint16_t*)(&finally);

    uint32_t result = sse_ptr[0] + sse_ptr[1] + sse_ptr[2] + sse_ptr[3]
                    + sse_ptr[4] + sse_ptr[5] + sse_ptr[6] + sse_ptr[7];

    printf("Result: %i numbers greater 42\n", result);

    return 0;
}

Breakpoint 1, main (argc=1, argv=0x7fff5fbff3b0) at example_comp.c:44
44      printf("Result: %i numbers greater 42\n", result);
(gdb) p/t sse_res
$1 = {11111111111111110000000000000000, 1111111111111111000000000000000011111111111111111111111111111111}
(gdb) p/t mask
$2 = {1000000000000000100000000000000010000000000000001, 1000000000000000100000000000000010000000000000001}
(gdb) p/t finally
$3 = {10000000000000000, 1000000000000000000000000000000010000000000000001}
(gdb) p result
$4 = 4
(gdb) 

私のgdbバージョン:GNU gdb 6.3.50-20050815 (Apple version gdb-1472) (Wed Jul 21 10:53:12 UTC 2010)

コンパイラフラグ:-Wall -g -O0 -mssse3 -msse4 -std=c99

4

1 に答える 1

2

あなたがここで何をしようとしているのか正確にはわかりませんが、私たちのためにそれを明確にすることができるかもしれません.

したがって、2 つの変数のそれぞれに 8 つの符号付き整数がパックされており、それより大きいかどうかをテストします。結果は、最初の 3 つが大きく、次は大きくなく、次の 3 つが大きく、最後の 3 つが大きくないことを示しているように見えます。(_mm_cmpgt_epi16 は、私が見つけた参照で符号付き整数を想定しています。)

次に、「それ」が真実かどうかを知りたいのですが、それが何を意味するのかわかりません。それらはすべて大きいということですか?(そうであれば、結果を MAX_VALUE または -1 などと比較できます。)

しかし、最後のステップは、一部のデータを区分的に右にシフトすることです。sse_res[0] と同じ変数ではないことに注意してください。代わりにそれをシフトすることを期待していましたか?

シフトする前にデータに何があったかを知らなければ、それが正しく機能したかどうかはわかりませんが、gdb は出力の先頭のゼロを省略していると思います。これにより、短い結果が説明されます。

0000000000011101    29    was 58 or 59
0000000000100100    36    was 72 or 73
0000000000011000    24    was 48 or 49
0000000000000011     3    was  6 or  7
0000000000100111    39    was 78 or 79
0000000000010110    22    was 44 or 45
0000000000100100    36    was 72 or 73
0000000000001111    15    was 30 or 31

これらの数字はおなじみですか?

アップデート:

更新されたコードをありがとう。整数が逆の順序でパックされているように見え、gdb 出力で先頭のゼロが省略されています。

于 2010-11-14T19:12:27.927 に答える