我试图了解SSE的转换是如何工作的,但我不明白输出gdb给了我。使用SSE4我有一个128位向量,保持8个16位无符号整数(使用uint16_t
)。然后我使用内在_mm_cmpgt_epi16
将它们与某个值进行比较,该函数将所有0或1位放入用于存储整数的位中。到目前为止一直很好,使用gdb我得到:
(gdb) p/t sse_res[0]
$3 = {1111111111111111111111111111111111111111111111110000000000000000, 1111111111111111111111111111111111111111111111110000000000000000}
然后我想将它们移到右边(这是正确的吗?)所以我得到一个数值为1,以防它是真的。然后GDB给我一个我不明白的输出:
(gdb) p/t shifted
$4 = {11101000000000010010000000000000110000000000000000011, 100111000000000001011000000000001001000000000000001111}
它与第一个的长度不一样,为什么会这样?为了尝试一下,我使用了以下内在函数将它向右移一位:
shifted = _mm_srli_epi16(sse_array[i], 1);
我预计它会在每个16位块的右端只移动一个零。
更新:
我写了一个小例子用bitmask来测试它,它运行正常,但我仍然不理解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
答案 0 :(得分:2)
我并不完全明白你在这里做了什么,但也许你可以为我们澄清一下。
因此,您有两个变量中包含的8个签名整数,您测试的变量大于。结果看起来它显示前三个更大,下一个不是,接下来的3个更大,最后一个不是。 (_mm_cmpgt_epi16假定我找到的引用中有符号整数。)
然后你想知道&#34;它&#34;是的,但我不确定你的意思。你的意思是他们都更伟大吗? (如果是这样,那么你可以将结果与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输出中保留。