GCC C 向量扩展:如何检查任何元素比较的结果是否为真,哪个?

GCC C vector extension: How to check if result of ANY element-wise comparison is true, and which?

我不熟悉 GCC 的 C 向量扩展。根据手册,以 (test = vec1 > vec2;) 形式将一个向量与另一个向量进行比较的结果是 "test" 在每个为假的元素中包含一个 0,在每个为真的元素中包含一个 -1 .

但是如何快速检查任何元素比较是否为真?而且,进一步,如何判断哪个是第一个比较为真的元素?

例如:

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

我想确定 "test" 是否包含任何真值(非零元素)。在这种情况下,我希望 "test" 减少为 true,因为存在一个元素,其 vec1 大于 vec2,因此测试中的一个元素包含 -1。

另外,或者,我想快速发现哪个元素未通过测试。在这种情况下,这只是数字 2。换句话说,我想测试第一个非零元素是哪个。

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

我想我们可以使用 simd 缩减加法命令 (?) 将向量中的所有内容求和为一个数字并将该和与 0 进行比较,但我不知道如何(或者是否有更快的方法).我猜想第二个问题需要某种形式的 argmax,但同样,我不知道如何指示 GCC 在向量上使用它。

来自神秘:

_mm_movemask_epi8()

它比 GCC 矢量扩展更便携。它由 Intel 标准化,因此它适用于每个主要编译器:GCC、Clang、MSVC、ICC 等...

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

为此,我们可以使用内部函数,通过使用内部函数,我们可以实现更快的代码执行速度。 Please refer below link

Clang 的矢量扩展使用 any 函数执行 good job

#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 是 not optimal for AVX512 though.

我认为 any function 是一个关键的向量函数,因此编译器应该提供一个内置函数,就像他们为随机播放所做的那样(例如 __builtin_shuffle 用于 GCC 和 __builtin_shufflevector 用于 clang)或者编译器应该足够聪明,能够像 Clang 那样找出最佳代码,至少对于 SSE 和 AVX 但不是 AVX512。

这是我在一个案例中最终使用的:

#define V_EQ(v1, v2) \
  ({ \
    __typeof__ (v1) v_d = (v1) != (v2); \
    __typeof__ (v_d) v_0 = { 0 }; \
    memcmp (&v_d, &v_0, sizeof v_d) == 0; \
  })

assert (V_EQ (v4ldblo, v4ldbli - 1));