我怎样才能向量化使用ARM NEON内在的IF块?(How can I vectorize an I

2019-09-25 16:34发布

我要处理的ARM处理器上的大阵浮点数,采用NEON技术来计算他们四在同一时间。 一切都很好的操作,如添加和繁殖,但如果我的计算进入一个IF块我该怎么办? 例:

// In the non-vectorized original code, A is an array of many floating-point
// numbers, which are calculated one at a time.  Now they're packed 
// into a vector and processed four at a time

...calculate A...

if (A > 10.f)
{
    A = A+5.f;
}
else
{
    A = A+10.f;
}

现在,这要是分支我执行? 如果某些载体中的值的正在处理的内容是大于10,有些是少? 它甚至有可能向量化这样的代码?

Answer 1:

我将描述如何给它的NEON内在的代码添加到答案为止。

  1. 一般情况下,你不做IF块逻辑基于并行寄存器的内容,因为一个值可能需要IF块的一个分支,并在同一个寄存器可能需要另一不同的值。 “心切执行”首先意味着做所有可能的计算,然后再决定导致实际在车道使用。 (记住,你不要做一个霓虹灯计算只有一个寄存器的车道得到任何东西。有在所有做任何计算,获取所有2或4通道来完成。)

  2. 做一个基于IF-计算,使用霓虹灯有条件的内在例如“大于”做一个位掩码,然后“选择”功能来填充最终结果根据位掩码

双下游[2] = {11.5,9.5};

float64x2_t AA= vld1q_f64(aval);       // an array with two 64-bit double values

float64x2 TEN= vmovq_n_f64(10.f);      // load a constant into a different array
float64x2 FIVE= vmovq_n_f64(5.f);      // load a constant into a different array

// Do both of the computations
float64x2 VALIFTRUE = vaddq_f64(AA, TEN);  // {21.5, 19.5}
float64x2 VALIFFALSE = vaddq_f64(AA, FIVE);  // {16.5, 14.5}


uint64x2_t IF1 = vcgtq_f64 (AA, TEN);  // comparison "(if A > 10.)"

vcgtq_f64的返回值是不是一组双打,但两个64位无符号整数。 它们实际上是一个位掩码,可以通过使用“按位选择”功能,如vbslq_f64。 IF1的前64位全为1的(在大于条件为真)和第二64位为全0。

AA = vbslq_f64(IF1, VALIFTRUE, VALIFFALSE);  // {21.5, 14.5}

...和AA的每个通道填充了两种VALIFTRUE或VALIFFALSE该车道适当。

  1. 如果急于执行实在是太慢了 - 在一个分支的计算是处理器时间非常昂贵的,你想避免做他们不惜一切,如果你能? 你必须以验证分支条件不是任何载体车道的真实,然后“if”语句跳过一个适当的计算。 也许别人可以如何好这个工作了在实践中发表评论。


Answer 2:

如果其他slaloms是几乎所有CPU的噩梦,尤其是对向量机等NEON不会对自己的任何条件分支。

因此,我们应用在这样的问题“心切的执行”。

  • 一个布尔面膜被创建
  • 无论ifelse块计算
  • “正确”的结果得到由掩码选择

我想这不会是问题转换aarch32下面的代码到内部函数。

//aarch32
    vadd.f32    vecElse, vecA, vecTen // vecTen contains 10.0f
    vcgt.f32    vecMask, vecA, vecTen
    vadd.f32    vecA, vecA, vecFive
    vbif        vecA, vecElse, vecMask

//aarch64
    fadd    vecElse.4s, vecA.4s, vecTen.4s
    fcmgt   vecMask.4s, vecA.4s, vecTen.4s
    fadd    vecA.4s, vecA.4s, vecFive.4s
    bif     vecA.16b, vecElse.16b, vecMask.16b


Answer 3:

通常,与SIMD分支逻辑您使用比较掩模,然后相应地选择替代的结果。 我给的伪码的例子,你可以根据需要将此转换为内部函数或ASM:

v5 = vector(5)              // set up some constant vectors
v10 = vector(10)
vMask = compare_gt(vA, v10) // generate mask for vector compare A > 10
va = add(vA, v10)           // vA = vA + 10 (all elements, unconditionally)
vtemp = and(v5, vMask)      // generate temp vector of 5 and 0 values based on mask
va = sub(vA, vTemp)         // subtract 5 from elements which are <= 10


文章来源: How can I vectorize an IF block using ARM Neon intrinsics?
标签: arm neon