开发者

SSE shifting integers

I'm trying to understand how shifting with SSE works, but I don't understand the output gdb gives me. Using SSE4 I have a 128bit vector holding 8 16bit unsigned integers (using uint16_t). Then I use the intrinsic _mm_cmpgt_epi16 to compare them against some value, this function puts in all 0 or 1 bits into the bits used to store the ints. So far so good, using gdb I get:

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

Then I would like to shift them to the right (is that correct?) so I just get a numerical value of 1 in case it's true. GDB then gives me an output which I don't understand:

(gdb) p/t shifted
$4 = {11101000000000010010000000000000110000000000000000011, 1001开发者_JS百科11000000000001011000000000001001000000000000001111}

It's not even of the same length as the first, why is this? Just to try it out I used the following intrinsic to shift it one bit to the right:

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

I expected it to shift in just one zero at the right end of every 16bit block.

Update:

I wrote a small example to test the thing with the bitmask, it works fine, but I still don't understand gdbs behavior:

#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) 

My gdb version: GNU gdb 6.3.50-20050815 (Apple version gdb-1472) (Wed Jul 21 10:53:12 UTC 2010)

Compiler flags: -Wall -g -O0 -mssse3 -msse4 -std=c99


I don't understand exactly what you're trying to do here, but maybe you can clarify it for us.

So, you have 8 signed integers packed in each of two variables, which you test for greater than. The result looks like it shows that the first 3 are greater, the next is not, the next 3 are greater, the last is not. (_mm_cmpgt_epi16 assumes signed integers in the reference I found.)

Then you want to tell if "it" is true, but I'm not sure what you mean by that. Do you mean they are all greater? (If so, then you could just compare the result against MAX_VALUE or -1 or something like that.)

But the last step is to shift some data to the right piecewise. Notice that is not the same variable as sse_res[0]. Were you expecting to shift that one instead?

Without knowing what was in the data before shifting, we can't tell if it worked correctly, but I assume that gdb is omitting the leading zeroes in its output, which would explain the shorter result.

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

Do these numbers look familiar?

Update:

Thanks for the updated code. It looks the integers are packed in the reverse order, and the leading zeroes left off in the gdb output.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜