我要处理的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,有些是少? 它甚至有可能向量化这样的代码?
我将描述如何给它的NEON内在的代码添加到答案为止。
一般情况下,你不做IF块逻辑基于并行寄存器的内容,因为一个值可能需要IF块的一个分支,并在同一个寄存器可能需要另一不同的值。 “心切执行”首先意味着做所有可能的计算,然后再决定导致实际在车道使用。 (记住,你不要做一个霓虹灯计算只有一个寄存器的车道得到任何东西。有在所有做任何计算,获取所有2或4通道来完成。)
做一个基于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该车道适当。
- 如果急于执行实在是太慢了 - 在一个分支的计算是处理器时间非常昂贵的,你想避免做他们不惜一切,如果你能? 你必须以验证分支条件不是任何载体车道的真实,然后“if”语句跳过一个适当的计算。 也许别人可以如何好这个工作了在实践中发表评论。
如果其他slaloms是几乎所有CPU的噩梦,尤其是对向量机等NEON不会对自己的任何条件分支。
因此,我们应用在这样的问题“心切的执行”。
- 一个布尔面膜被创建
- 无论
if
与else
块计算 - “正确”的结果得到由掩码选择
我想这不会是问题转换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
通常,与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