Подтвердить что ты не робот

Расширение вектора GCC C: как проверить, является ли результат ЛЮБОГО элементарного сравнения истинным, а какой?

Я новичок в расширении вектора GCC C. Согласно руководству, результат сравнения одного вектора с другим в форме (test = vec1 > vec2;) заключается в том, что "test" содержит 0 в каждом элементе, который является ложным, и -1 в каждом элементе, который является истинным.

Но как быстро проверить, верно ли ANY из сравнения элементов? И, далее, как определить, который является первым элементом, для которого было выполнено сравнение?

Например, с помощью

vec1 = {1,1,3,1};
vec2 = {1,2,2,2};
test = vec1 > vec2;

Я хочу определить, содержит ли "тест" любую правду (ненулевые элементы). В этом случае я хочу, чтобы "test" сменился на true, потому что существует элемент, для которого vec1 больше vec2 и, следовательно, элемент в тесте, содержащий -1.

Кроме того, или, альтернативно, я хочу быстро обнаружить, что элемент WHICH не прошел тест. В этом случае это просто будет число 2. Говоря другим способом, я хочу проверить, который является первым ненулевым элементом.

int hasAnyTruth = ...; // should be non-zero. "bool" works too since C99
int whichTrue = ...; // should contain 2, because test[2] == -1

Я предполагаю, что мы могли бы использовать команду simd reduce-addition (?), чтобы суммировать все в векторе в число и сравнивать эту сумму с 0, но я не знаю, как (или если есть более быстрый способ). Я предполагаю, что для второго вопроса необходим какой-то вид argmax, но опять же, я не знаю, как поручить GCC использовать его на векторах.

4b9b3361

Ответ 1

От мистического:

_mm_movemask_epi8()

Он более переносимый, чем расширения GCC. Он стандартизирован Intel, поэтому он будет работать в каждом крупном компиляторе: GCC, Clang, MSVC, ICC и т.д.

http://software.intel.com/sites/landingpage/IntrinsicsGuide

Ответ 2

Расширение вектора Clang выполняет хорошую работу с помощью функции any.

#if defined(__clang__)
typedef int64_t vli __attribute__ ((ext_vector_type(VLI_SIZE)));
typedef double  vdf __attribute__ ((ext_vector_type(VDF_SIZE)));
#else
typedef int32_t vsi __attribute__ ((vector_size (SIMD_SIZE)));
typedef int64_t vli __attribute__ ((vector_size (SIMD_SIZE)));
#endif

static bool any(vli const & x) {
  for(int i=0; i<VLI_SIZE; i++) if(x[i]) return true;
  return false;
}

Сборка

any(long __vector(4) const&): # @any(long __vector(4) const&)
  vmovdqa ymm0, ymmword ptr [rdi]
  vptest ymm0, ymm0
  setne al
  vzeroupper
  ret

Хотя pmovmskb может быть лучшим выбором ptest по-прежнему является большим улучшением по сравнению с тем, что GCC делает

any(long __vector(4) const&):
  cmp QWORD PTR [rdi], 0
  jne .L5
  cmp QWORD PTR [rdi+8], 0
  jne .L5
  cmp QWORD PTR [rdi+16], 0
  jne .L5
  cmp QWORD PTR [rdi+24], 0
  setne al
  ret
.L5:
  mov eax, 1
  ret

GCC должен это исправить. Clang не оптимален для AVX512, хотя.

any function Я бы сказал, что это критическая векторная функция, поэтому компиляторы должны либо предоставить встроенную функцию, как для тасования (например, __builtin_shuffle для GCC и __builtin_shufflevector для clang), или компилятор должен быть достаточно умным, чтобы определить оптимальный код, например Clang, по крайней мере, для SSE и AVX, но не для AVX512.

Ответ 3

Для этого мы можем использовать внутренние функции, используя встроенные функции, мы можем добиться большей скорости выполнения кода. См. ссылку ниже