我是GCC的C矢量扩展的新手.根据手册,将一个向量与另一个向量进行比较的结果(test = vec1> vec2;)是"test"在每个元素中包含0,为false,每个元素中为-1为真.
但是如何快速检查是否有任何元素比较是真的?而且,进一步说,如何判断哪个是比较真实的第一个元素?
例如,用:
vec1 = {1,1,3,1};
vec2 = {1,2,2,2};
test = vec1 > vec2;
Run Code Online (Sandbox Code Playgroud)
我想确定"test"是否包含任何真值(非零元素).在这种情况下,我希望"test"减少为true,因为存在一个vec1大于vec2的元素,因此test中的元素包含-1.
另外,或者,我想快速发现WHICH元素未通过测试.在这种情况下,这只是数字2.换句话说,我想测试哪个是第一个非零元素.
int hasAnyTruth = ...; // should be non-zero. "bool" works too since C99
int whichTrue = ...; // should contain 2, because test[2] == -1
Run Code Online (Sandbox Code Playgroud)
我想我们可以使用simd reduction-addition命令(?)将向量中的所有内容加到一个数字中并将该总和与0进行比较,但我不知道如何(或者是否有更快的方法).我猜第二个问题需要某种形式的argmax,但同样,我不知道如何指示GCC在矢量上使用它.
当使用C的GCC向量扩展时,如何检查向量上的所有值是否为零?
例如:
#include <stdint.h>
typedef uint32_t v8ui __attribute__ ((vector_size (32)));
v8ui*
foo(v8ui *mem) {
v8ui v;
for ( v = (v8ui){ 1, 1, 1, 1, 1, 1, 1, 1 };
v[0] || v[1] || v[2] || v[3] || v[4] || v[5] || v[6] || v[7];
mem++)
v &= *(mem);
return mem;
}
Run Code Online (Sandbox Code Playgroud)
SSE4.2具有PTEST允许运行像用作for条件的测试的指令,但是GCC生成的代码只是解包向量并逐个检查单个元素:
.L2:
vandps (%rax), %ymm1, %ymm1
vmovdqa %xmm1, %xmm0
addq $32, %rax
vmovd %xmm0, %edx
testl %edx, %edx
jne .L2
vpextrd $1, %xmm0, %edx …Run Code Online (Sandbox Code Playgroud) 鉴于:
#include <string.h>
bool test_data(void *data)
{
return memcmp(data, "abcd", 4) == 0;
}
Run Code Online (Sandbox Code Playgroud)
编译器可以将其优化为:
test_data:
cmpl $1684234849, (%rdi)
sete %al
ret
Run Code Online (Sandbox Code Playgroud)
这很好。
但如果我使用我自己的memcmp()(而不是来自<string.h>),编译器无法将其优化为单个cmpl指令。相反,它这样做:
test_data:
cmpl $1684234849, (%rdi)
sete %al
ret
Run Code Online (Sandbox Code Playgroud)
test_data:
cmpb $97, (%rdi)
jne .L5
cmpb $98, 1(%rdi)
jne .L5
cmpb $99, 2(%rdi)
jne .L5
cmpb $100, 3(%rdi)
sete %al
ret
.L5:
xorl %eax, %eax
ret
Run Code Online (Sandbox Code Playgroud)
链接: https: //godbolt.org/z/Kfhchr45a
c ×3
gcc ×2
assembly ×1
avx2 ×1
comparison ×1
memcmp ×1
optimization ×1
performance ×1
sse ×1
x86-64 ×1