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 等...
为此,我们可以使用内部函数,通过使用内部函数,我们可以实现更快的代码执行速度。
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));
我不熟悉 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 等...
为此,我们可以使用内部函数,通过使用内部函数,我们可以实现更快的代码执行速度。 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));