Как работает встроенная функция _mm_cmpgt_epi64 - PullRequest
0 голосов
/ 14 октября 2018

Я использую встроенную функцию _mm_cmpgt_epi64 для реализации 128-битного сложения, а позже 256-битного.Глядя на результат этого внутреннего, что-то меня озадачивает.

Я не понимаю, почему вычисленная маска такая, какая она есть.

const __m128i mask = _mm_cmpgt_epi64(bflip, sumflip);

А вот вывод в моем отладчике:

(lldb) p/x bflip
(__m128i) $1 = (0x00000001, 0x80000000, 0x00000000, 0x80000000)
(lldb) p/x sumflip
(__m128i) $2 = (0x00000000, 0x80000000, 0xffffffff, 0x7fffffff)
(lldb) p/x mask
(__m128i) $3 = (0xffffffff, 0xffffffff, 0x00000000, 0x00000000)

Для первой 64-битной полосы (63:0) я в порядке.Но почему вторая полоса (127:64) тоже не полна?

Мне кажется, что 0x8000000000000000> 0x7fffffffffffffff.

1 Ответ

0 голосов
/ 14 октября 2018

Кажется, вы печатаете его 32-битными порциями, а не 64-битными, так что это странно.

Но в любом случае, это со знаком дополнение к двум целочисленное сравнение, как описано в руководстве: http://felixcloutier.com/x86/PCMPGTQ.html

0x8000000000000000 - самое отрицательное 64-разрядное целое число, а 0x7fffffffffffffff - самое большое положительное.

Если вы хотитебеззнаковое сравнение, вам нужно сместить диапазон обоих входов, щелкнув их знаковый бит.Логически это вычитает 2 ^ 63, чтобы перейти от 0..2 ^ 64-1 до -2 ^ 63 .. 2 ^ 63-1.Но мы можем сделать это с более эффективным XOR, потому что XOR - это добавление без переноса, и перенос / заимствование уходит в конец регистра.

const __m128i rangeshift = _mm_set1_epi64x(0x8000000000000000);
const __m128i mask = _mm_cmpgt_epi64(_mm_xor_si128(bflip, rangeshift), _mm_xor_si128(sumflip, rangeshift));

Или используйте AVX512F __mmask8 _mm512_cmp[eq|ge|gt|le|lt|neq]_epu64_mask( __m512i a, __m512i b)

...