检查向量是否包含大于零的任何元素

时间:2014-10-20 20:30:36

标签: c vector avx

如果有人可以帮助编写一个接收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;
}

1 个答案:

答案 0 :(得分:3)

如果您要对结果进行分支,那么使用“传统”比较/ movemask /整数测试通常会减少uops,就像使用SSE1一样。

__m256 vcmp = _mm256_cmp_ps(_mm256_setzero_ps(), x, _CMP_LT_OQ);
int cmp = _mm256_movemask_ps(vcmp);
if (cmp)
    return 1;

这通常会编译为

vcmplt_oqps  ymm2, ymm0, ymm1
vpmovmskb    eax, ymm2

test         eax,eax
jnz      .true_branch

这些都是单uop指令,以及支持AVX的Intel和AMD CPU上的test / jnz宏保险丝,所以这只有3个uop(在Intel上)。

请参阅Agner Fog's instruction tables + microarch guide以及https://stackoverflow.com/tags/x86/info链接的其他指南。

您也可以使用PTEST,但这种情况效率较低。见_mm_testc_ps and _mm_testc_pd vs _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;
}

testz内在因素是PTEST。它根据args的AND和AND NOT的结果直接设置ZF和CF标志。当vcmp具有任何非零位时,testz内在函数为真。 (只有当vcmpps放在那里时才会这样。)

带有ymm regs的

VPTEST仅适用于AVX。即使它看起来像向量整数指令,也不需要AVX2。

这将编译为类似

的内容
vcmplt_oqps  ymm2, ymm0, ymm1
vptest       ymm2, ymm2
jnz      .true_branch

可能比上面的代码大小更小,但这实际上是4 uops而不是3.如果你使用setnzcmovnz,宏融合将不是一个因素,所以{ {1}}会收支平衡。正如我上面提到的,ptest的主要用例是在没有比较指令且没有AVX的情况下使用它。

检查全零的向量(ptest / pcmpeqb xmm0,xmm1 / pmovmskb eax, xmm1)的替代方法必须销毁其中一个没有AVX的输入向量,因此需要额外的{ {1}}如果在测试后仍需要两者,请复制指令。

test eax,eax浮点位黑客

我认为对于这个特定的测试,可能会跳过比较指令并直接使用movdqa来查看是否有任何ptest元素的符号位未设置,但有些非零其他地方。

实际上不,这个想法不起作用,因为它不尊重元素边界。它无法区分带有正元素的向量与带有vptest元素的向量(符号位清除)和另一个带负值的元素(其他位置集)之间的区别。

float设置CF=bool(~src1 & src2) and ZF=(src1 & src2)。我在想src1 = +0.0可以告诉我们关于符号位和非符号位的有用信息,我们可以用检查CF和ZF的条件进行测试。例如ja:CF = 0且ZF = 0。实际上没有x86条件只有在CF = 1 ZF = 0时才是真的,所以这是另一个问题。

同样vptest为假,但NaN有一些设置位。 (指数全1,尾数非零,符号位=不关心所以可以有+ NaN和-NaN)。如果这是唯一的问题,那么在不需要NaN处理的情况下,这仍然有用。