Я запускаю скамейку вычислений с использованием SIMD-инструкций. Эти инструкции возвращают вектор из 16 байт, как результат, названных compare
, причем каждый байт является 0x00
или 0xff
:Извлечь заданную позицию байтов из SIMD-вектора
0 1 2 3 4 5 6 7 15 16
compare : 0x00 0x00 0x00 0x00 0xff 0x00 0x00 0x00 ... 0xff 0x00
Bytes набором для 0xff
значит мне нужно запустить функцию do_operation(i)
с я быть положением байта.
Например, выше compare
вектор средней, мне нужно запустить эту последовательность операций:
do_operation(4);
do_operation(15);
Вот быстрое решение я придумал до сих пор:
for(...) {
//
// SIMD computations
//
__m128i compare = ... // Result of SIMD computations
// Extract high and low quadwords for compare vector
std::uint64_t cmp_low = (_mm_cvtsi128_si64(compare));
std::uint64_t cmp_high = (_mm_extract_epi64(compare, 1));
// Process low quadword
if (cmp_low) {
const std::uint64_t low_possible_positions = 0x0706050403020100;
const std::uint64_t match_positions = _pext_u64(
low_possible_positions, cmp_low);
const int match_count = _popcnt64(cmp_low)/8;
const std::uint8_t* match_pos_array =
reinterpret_cast<const std::uint8_t*>(&match_positions);
for (int i = 0; i < match_count; ++i) {
do_operation(i);
}
}
// Process high quadword (similarly)
if (cmp_high) {
const std::uint64_t high_possible_positions = 0x0f0e0d0c0b0a0908;
const std::uint64_t match_positions = _pext_u64(
high_possible_positions, cmp_high);
const int match_count = _popcnt64(cmp_high)/8;
const std::uint8_t* match_pos_array =
reinterpret_cast<const std::uint8_t*>(&match_positions);
for(int i = 0; i < match_count; ++i) {
do_operation(i);
}
}
}
Я начинаю с извлечением первого и второго 64-битных целых чисел из 128-битного вектора (cmp_low
и cmp_high
). Затем я использую popcount
для вычисления количества байтов, установленного на 0xff
(количество бит, установленное в 1, деленное на 8). Наконец, я использую pext
, чтобы получить позиции, без нулей, например:
0x0706050403020100
0x000000ff00ff0000
|
PEXT
|
0x0000000000000402
Я хотел бы найти быстрое решение для извлечения позиций байт, установленных для 0xff
compare
в векторе. Точнее, очень часто только 0, 1 или 2 байта установлены в 0xff
в compare
vector, и я хотел бы использовать эту информацию, чтобы избежать некоторых ветвей.
Какой компилятор? – didierc
Я использую GCC 4.9.1, но я в порядке с другими версиями GCC или Clang. – Xion345
Почему бы «do_operation» не использовать SIMD? –