Использование __builtin_popcount или других встроенных функций для обработки результата растрового изображения сравнения _mm256_movemask_pd? - PullRequest
0 голосов
/ 08 октября 2018

У меня есть этот фрагмент кода, и я хотел бы в конечном итоге реализовать модифицированную версию алгоритма (ов) оценки битовой маски из этого документа - Адаптация древовидных структур для обработки с помощью инструкций SIMD

#include <stdint.h>
#include <immintrin.h>
#include <assert.h>
#include <limits.h>
#include <math.h>
#include <stdalign.h>

int main(void)
{
    __m256d avx_creg, res, avx_sreg;
    int bitmask;
    uint64_t key = 503;

    avx_sreg = _mm256_castsi256_pd(_mm256_set1_epi64x(key));
    alignas(32) uint64_t v[4]; 
    _mm256_store_pd((double*)v, avx_sreg);
    printf("v2_u64: %lld %lld %lld %lld\n", v[0], v[1],v[2],v[3]);
    uint64_t b[4]= {500,505,510,515};
    avx_creg = _mm256_castsi256_pd(
                   _mm256_loadu_si256((__m256i const *)&b));
    //
    alignas(32) uint64_t v1[4]; 
    _mm256_store_pd((double*)v1, avx_creg);
    printf("v2_u64: %lld %lld %lld %lld\n", v1[0], v1[1],v1[2],v1[3]);

    res      = _mm256_cmp_pd(avx_sreg, avx_creg, 30);
    bitmask  = _mm256_movemask_pd(res);
    int mmask = __builtin_popcount(bitmask);
    printf("mmask is %d\n",mmask);

    return 0;
}

Приведенный выше код печатает значение mmask как 1. Так что здесь я не совсем уверен.Должен ли я интерпретировать число «1» как индекс массива, где элемент массива больше, чем ключ ввода, или это относится к количеству установленных битов?

Если, например, я изменяюключ к 499 маске печатается как 0.

Наконец, если я изменю ключ на 517, значение маски будет 4.

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

1 Ответ

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

movemask создает целочисленное растровое изображение, беря старший бит каждого элемента из вектора.Напечатайте его как шестнадцатеричное или основание-2, чтобы увидеть его лучше.

Если вам важны только 0 против ненулевых значений, просто отметьте if(bitmask != 0)

или if(bitmask == 0x0f), чтобы проверить,они все правда.(4 бита для вектора из 4 элементов).


Используйте popcount, чтобы узнать, сколько было правдой.__builtin_popcnt подсчитывает количество установленных бит на его входе.

Используйте __builtin_ctz, чтобы найти позицию первого элемента, где сравнение было истинным.(Подсчет от низкого до высокого адреса памяти, если векторы были загружены из памяти).Помните, что __builtin_ctz имеет смысл только для ненулевых входных данных.например, в цикле memchr вы должны использовать ctz только после выхода из цикла поиска на _mm256_movemask_epi8(cmp_result) == 0, чтобы установить, что в этом векторе есть совпадение.(epi8, потому что я говорю о цикле поиска байтов, в отличие от ваших упакованных - double сравнений).

Возможно, вы захотите использовать BMI1 _lzcnt_u32(bitmask), чтобы получитьопределенный результат (32 ведущих нуля) для битовой маски = 0, если вам уже требуется AVX2.(Поскольку я думаю, что все процессоры AVX2 имеют BMI1.)


Чтобы выполнить итерации по совпадениям , вы можете использовать операцию сброса наименьшего младшего установленного бита, и если еще естьесли бит установлен, то ctz, чтобы узнать, какой из них.См. Сброс младшего установленного бита числа .

x & (x-1) будет эффективно компилироваться в инструкцию BMI1 blsr, если вы компилируете с включенным BMI1, например, с -march=haswell.

(чтобы это работало хорошо, вы определенно хотите, чтобы movemask соответствовал размеру вашего векторного элемента, поэтому для 64-битного целого числа приведите ваш вектор к _pd, чтобы вы могли использовать _mm256_movemask_pd.)

...