Сравнение 64-разрядных целых чисел без знака AVX2 - PullRequest
0 голосов
/ 03 сентября 2018

Я пытаюсь сравнить два __m256i (4 упакованных 64-разрядных целых числа). Для этого я использую функцию _mm256_cmpgt_epi64 .

Функция работает, как и ожидалось, за исключением нескольких сравнений, как если бы она не учитывала старший бит 64-разрядного целого числа. Как показано ниже во втором и третьем сравнениях.

Здесь MCVE, где я ожидаю, что каждое 64-разрядное целое число из a будет больше, чем его равноправный элемент из b (таким образом, cp должно быть 0xFFF...FFF):

#include <immintrin.h>
#include <x86intrin.h>
#include <stdio.h>
#include <inttypes.h>

// gcc mcve.c -mavx2 -madx && ./a.out

int print_avx2_hex256(__m256i ymm)
{
    const size_t n = sizeof(__m256i) / sizeof(u_int64_t);
    u_int64_t buffer[n];
    _mm256_storeu_si256((__m256i*)buffer, ymm);
    for (int i=0; i<n; ++i)
        printf("%016"PRIx64" ", buffer[i]);
    printf("\n");

    return 0;
}

int compare(__m256i a, __m256i b)
{
    __m256i cp = _mm256_cmpgt_epi64(a,b);

    print_avx2_hex256(cp); // Comparison
    print_avx2_hex256(a);
    print_avx2_hex256(b);

    return 0;
}

int main()
{
    u_int64_t _a[4] = {0xf, 0xf000000000000000, 0xd00000000000000d, 0x0f00000000000000};
    u_int64_t _b[4] = {0x2, 0x2000000000000000, 0x2000000000000002, 0x0200000000000000};

    __m256i a   = _mm256_setr_epi64x(_a[0], _a[1], _a[2], _a[3]);
    __m256i b   = _mm256_setr_epi64x(_b[0], _b[1], _b[2], _b[3]);

    compare(a,b);
    return 0;
}

Однако мой вывод выглядит следующим образом (в порядке cp, a, b):

ffffffffffffffff 0000000000000000 0000000000000000 ffffffffffffffff 
000000000000000f f000000000000000 d00000000000000d 0f00000000000000 
0000000000000002 2000000000000000 2000000000000002 0200000000000000 

Я не знаком с функциями Intel Intrinsics, поэтому, если кто-то может сказать мне, что я делаю неправильно, это будет оценено :))

1 Ответ

0 голосов
/ 03 сентября 2018

Ваша проблема в том, что _mm256_cmpgt_epi64 сравнивает знаковые целые числа, поэтому, если вы установите старший бит на одном из i64, он считается отрицательным. Например, 0xf000000000000000 отрицательно, 0x2000000000000000 нет, а _mm256_cmpgt_epi64 (справедливо) говорит вам, что последнее больше.

Не похоже, что есть строго эквивалентная функция, которая сравнивает целые числа без знака, но вы можете использовать _mm256_cmpgt_epu64_mask, который возвращает битовое поле __mmask8.

РЕДАКТИРОВАТЬ: забыл упомянуть, что _mm256_cmpgt_epu64_mask требует AVX512, который может быть недоступен для вас.

...