我想在ARM处理器上处理大量的浮点数, 使用霓虹灯技术一次四个计算它们。对于像加法和乘法这样的操作,一切都很好,但如果我的计算进入IF块,我该怎么办?例如:
i = 9.60000
现在,我执行哪个IF分支?如果正在处理的向量中的某些值大于10而某些值较小,该怎么办?甚至可以像这样对代码进行矢量化吗?
答案 0 :(得分:2)
到目前为止,我将通过描述如何在Neon内在函数中对其进行编码来添加答案。
通常,您不会根据并行寄存器内容执行IF块逻辑,因为一个值可能需要IF块的一个分支,而同一个寄存器中的不同值可能需要另一个。 “急切执行”意味着首先进行所有可能的计算,然后确定哪些结果实际用于哪个通道。 (请记住,通过仅对寄存器的一个通道进行氖计算,您无法获得任何结果。任何必须完成的计算,都可以完成所有2或4个通道。)
要进行基于IF的计算,请使用Neon条件内在函数,例如: “大于”以制作位掩码,然后使用“选择”函数根据位掩码填充最终结果
double aval [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 :(得分:1)
If-else障碍赛对于几乎所有的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
答案 2 :(得分:0)
通常使用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