Тернарный оператор для расширенных векторов clang - программирование

Тернарный оператор для расширенных векторов clang

Я пробовал играть с clang расширенными векторами. Тройной оператор должен работать, но он не работает для меня. Пример:

int main()
{
  using int4 = int __attribute__((ext_vector_type(4)));

  int4 a{0, 1, 3, 4};
  int4 b{2, 1, 4, 5};

  auto const r(a - b ? a : b);

  return 0;
}

Просьба привести примеры того, как я могу заставить его работать, например, работает под OpenCL. Я использую clang-3.4.2.

Ошибка:

t.cpp:8:16: error: value of type 'int __attribute__((ext_vector_type(4)))' is not contextually convertible to 'bool'
  auto const r(a - b ? a : b);
               ^~~~~
1 error generated.
4b9b3361

Ответ 1

Вы можете зациклить элементы прямо в Clang. Вот решение для GCC и Clang.

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

#if defined(__clang__)
typedef float float4 __attribute__ ((ext_vector_type(4)));
typedef   int   int4 __attribute__ ((ext_vector_type(4)));
#else
typedef float float4 __attribute__ ((vector_size (sizeof(float)*4)));
typedef   int   int4 __attribute__ ((vector_size (sizeof(int)*4)));
#endif

float4 select(int4 s, float4 a, float4 b) {
  float4 c;
  #if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__clang__)
  c = s ? a : b;
  #else
  for(int i=0; i<4; i++) c[i] = s[i] ? a[i] : b[i];
  #endif
  return c;
}

Оба генерируют

select(int __vector(4), float __vector(4), float __vector(4)):
  pxor xmm3, xmm3
  pcmpeqd xmm0, xmm3
  blendvps xmm1, xmm2, xmm0
  movaps xmm0, xmm1
  ret

Но с AVX512 лучше использовать маски (например, __mmask16).

Ответ 2

Это работает в крайнем случае:

auto const diff = a-b;
auto const ra( - (diff!=zero) * a - (diff==zero) *b);

Я предполагаю, что это ошибка в компиляторе или в документации, которую вы связали.

Ответ 3

В конце я пошел с этим:

#if defined(__clang__)
template <typename U, typename V>
constexpr inline std::enable_if_t<
  !std::is_arithmetic<V>{},
  V
>
select(V const a, V const b, U const c) noexcept
{
  return V((c & U(a)) | (~c & U(b)));
}
#else
template <typename U, typename V>
constexpr inline std::enable_if_t<
  !std::is_arithmetic<V>{},
  V
>
select(V const a, V const b, U const c) noexcept
{
  return c ? a : b;
}
#endif

То же самое можно было бы сделать и другими способами, например, используя трюк индексов, но он может не очень оптимизироваться (я не хотел никаких условностей там).