如果有人可以帮助编写一个接收AVX向量的函数并检查它是否包含任何大于零的元素,我将感激不尽.
我编写了以下代码,但它不是最佳的,因为它存储元素然后操纵它.矢量应该作为一个整体进行检查.
int check(__m256 vector)
{
float * temp;
posix_memalign ((void **) &temp, 32, 8 * sizeof(float));
_mm256_store_ps( temp, vector );
int flag=0;
for(int k=0; k<8; k++)
{
flag= ( (temp[k]>0) ? 1 : 0 );
if (flag==1) return 1;
}
free( temp);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果您要对结果进行分支,则使用“传统”比较/移动掩码/整数测试通常会减少微指令,就像使用 SSE1 一样。
__m256 vcmp = _mm256_cmp_ps(_mm256_setzero_ps(), x, _CMP_LT_OQ);
int cmp = _mm256_movemask_ps(vcmp);
if (cmp)
return 1;
Run Code Online (Sandbox Code Playgroud)
这通常会编译成类似的东西
vcmplt_oqps ymm2, ymm0, ymm1
vpmovmskb eax, ymm2
test eax,eax
jnz .true_branch
Run Code Online (Sandbox Code Playgroud)
这些都是单 uop 指令,以及支持 AVX 的 Intel 和 AMD CPU 上的 test/jnz 宏熔断,因此总共只有 3 个 uop(在 Intel 上)。
请参阅Agner Fog 的指令表 + 微架构指南以及https://stackoverflow.com/tags/x86/info链接的其他指南。
您也可以使用 PTEST,但在这种情况下效率较低。请参阅_mm_testc_ps 和 _mm_testc_pd 与 _mm_testc_si128
没有 AVX,ptest
可以方便地检查寄存器是否全零,而不需要额外的指令来复制它(因为它直接设置整数标志)。但由于它是 2 uop,并且不能与jcc
分支指令进行宏融合,所以它实际上比上面的更糟糕:
// don't use, sub-optimal
__m256 vcmp = _mm256_cmp_ps(_mm256_setzero_ps(), x, _CMP_LT_OQ);
if (!_mm256_testz_si256(vcmp, vcmp)) {
return 1;
}
Run Code Online (Sandbox Code Playgroud)
内在testz
是PTEST
. 它直接根据其参数的 AND 和 AND NOT 的结果设置 ZF 和 CF 标志。vcmp
当有任何非零位时, testz 内在函数为 true 。(只有当把一些东西放在那里时才会这样vcmpps
。)
VPTEST
with ymm regs 仅适用于 AVX。尽管 AVX2 看起来像向量整数指令,但它并不是必需的。
这将编译成类似的东西
vcmplt_oqps ymm2, ymm0, ymm1
vptest ymm2, ymm2
jnz .true_branch
Run Code Online (Sandbox Code Playgroud)
代码大小可能比上面的要小,但这实际上是 4 uop,而不是 3。如果您使用setnz
or cmovnz
,则宏融合不会成为一个因素,因此ptest
将实现收支平衡。正如我上面提到的,主要用例ptest
是当您可以在没有比较指令且没有 AVX 的情况下使用它时。
检查向量是否全零 ( pcmpeqb xmm0,xmm1
/ pmovmskb eax, xmm1
/ test eax,eax
) 的另一种方法必须在没有 AVX 的情况下销毁其中一个输入向量,因此movdqa
如果在测试后仍然需要这两个向量,则需要额外的指令来复制。
ptest
浮点位黑客我认为对于这个特定的测试,可能可以跳过比较指令并vptest
直接使用来查看是否有任何float
元素的符号位未设置,但其他地方有一些非零位。
实际上不,这个想法行不通,因为它不尊重元素边界。它无法区分具有正元素的向量与具有元素+0.0
(符号位清除)和另一个负元素(其他位设置)的向量之间的区别。
vptest
设置CF=bool(~src1 & src2)
和 ZF=(src1 & src2)
。我认为 src1=set1(0x7FFFFFFF)
可以告诉我们一些关于符号位和非符号位的有用信息,我们可以使用检查 CF 和 ZF 的条件来测试这些信息。例如ja
:CF=0 且 ZF=0。不过,实际上并不存在仅在 CF=1和ZF=0 时才成立的 x86 条件,因此这是另一个问题。
也是NaN > 0
false,但 NaN 有一些设置位。(指数全 1,尾数非零,符号位 = 不关心,因此可以有 +NaN 和 -NaN)。如果这是唯一的问题,那么在不需要 NaN 处理的情况下这仍然很有用。