如果比较,ARM霓虹灯armv7 SIMD指令

时间:2016-07-02 13:58:48

标签: arm vectorization simd neon intrinsics

如何为以下循环编写霓虹灯代码:

<table class="table text-center">

我尝试使用vbslq_f32,但我必须逐个构造它的参数。为什么NEON没有提供更方便的工作方式?有没有更好的方法呢?

float sfx[64], delta = 9.9e-5;
for(int i = 0; i < 64; i++) {
    if (sfx[i] < delta) {
        abq[i] = 1.0/delta;
    } else {
        abq[i] = 1.0/sfx[i];
    }
}

1 个答案:

答案 0 :(得分:3)

实际上,通过一次执行一个操作的操作来打败矢量化点有点愚蠢。这也几乎是不必要的。

此:

vcon = vsetq_lane_u32((vgetq_lane_f32(vsfx,0)<delta), vcon, 0);
vcon = vsetq_lane_u32((vgetq_lane_f32(vsfx,1)<delta), vcon, 1);
vcon = vsetq_lane_u32((vgetq_lane_f32(vsfx,2)<delta), vcon, 2);
vcon = vsetq_lane_u32((vgetq_lane_f32(vsfx,3)<delta), vcon, 3);

这只是一种愚蠢的方式:

float32x4_t vdelta = vdupq_n_f32(delta);
// vector compare less than
vcon = vcltq_f32(vsfx, vdelta);

分区有点尴尬,因为NEON没有分区指令,但我们实际上并不需要通用分区;这种互惠行动:

vsfxdiv = vsetq_lane_f32((1.0/vgetq_lane_f32(vsfx,0)), vsfxdiv, 0);
vsfxdiv = vsetq_lane_f32((1.0/vgetq_lane_f32(vsfx,1)), vsfxdiv, 1);
vsfxdiv = vsetq_lane_f32((1.0/vgetq_lane_f32(vsfx,2)), vsfxdiv, 2);
vsfxdiv = vsetq_lane_f32((1.0/vgetq_lane_f32(vsfx,3)), vsfxdiv, 3);
可以改为将

矢量化为:

// reciprocal estimate; if precision isn't all that critical, this may suffice on its own
vsfxdiv = vrecpeq_f32(vsfx);
// otherwise, as a general rule of thumb, two Newton-Raphson iterations is
// probably sufficient for single-precision floats
vsfxdiv = vmulq_f32(vsfxdiv, vrecpsq_f32(vsfxdiv, vsfx));
vsfxdiv = vmulq_f32(vsfxdiv, vrecpsq_f32(vsfxdiv, vsfx));

现在,当你考虑到这一点时,这个特殊情况可以进一步简化:

if (sfx[i] < delta) {
    abq[i] = 1.0/delta;
} else {
    abq[i] = 1.0/sfx[i];
}

就是这样:

abq[i] = 1.0/max(delta, sfx[i]);

这意味着显式比较和条件选择可以完全省略,我们最终得到:

float32x4_t vdelta = vdupq_n_f32(delta);
for(int i = 0; i < 64; i+=4) {
    float32x4_t vsfx, vabq;

    vsfx = vld1q_f32((const float32_t*)(sfx+i));
    vsfx = vmaxq_f32(vsfx, vdelta);

    vabq = vrecpeq_f32(vsfx);
    vabq = vmulq_f32(vabq, vrecpsq_f32(vabq, vsfx));
    vabq = vmulq_f32(vabq, vrecpsq_f32(vabq, vsfx));

    vst1q_f32((abq+i), vabq);
}