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