带中频比较的ARM Neon armv7 SIMD指令

带中频比较的ARM Neon armv7 SIMD指令,arm,vectorization,simd,neon,intrinsics,Arm,Vectorization,Simd,Neon,Intrinsics,如何为以下循环编写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]; } } float-sfx[64],delta=9.9e-5; 对于(int i=0;i

如何为以下循环编写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];
    }
}
float-sfx[64],delta=9.9e-5;
对于(int i=0;i<64;i++){
if(sfx[i]
我尝试使用vbslq_f32,但我必须逐个构造它的参数。为什么霓虹灯不能提供一种更方便的方式来完成这项工作?有没有更好的办法

float32x4_t vdelta = vdupq_n_f32((float)1.0/delta);
for(int i = 0; i < 64; i+=4) {
    float32x4_t vsfx = vld1q_f32((const float32_t*)(sfx+i));
    uint32x4_t vcon;
    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 vsfxdiv;
    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);

    float32x4_t vabq = vblsq_f32(vcon, vsfxdiv, vdelta);
    vst1q_f32((abq+i), vabq);
}
float32x4_t vdelta=vdupq_n_f32((float)1.0/delta);
对于(int i=0;i<64;i+=4){
float32x4_t vsfx=vld1q_f32((常量float32_t*)(sfx+i));
uint32x4_t vcon;

vcon=vsetq_lane_u32((vgetq_lane_f32(vsfx,0)事实上,通过一次执行一个车道的操作来克服矢量化点有点愚蠢。这也基本上是不必要的

这:

除法有点尴尬,因为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];
}
这意味着可以完全省略显式比较和条件选择,我们最终得出以下结论:

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);
}
float32x4_t vdelta=vdupq_n_f32(增量);
对于(int i=0;i<64;i+=4){
浮动32x4_t vsfx,vabq;
vsfx=vld1q_f32((常量浮点32_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);
}

事实上,通过一次执行一条车道的操作来击败矢量化点有点愚蠢。这也基本上是不必要的

这:

除法有点尴尬,因为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];
}
这意味着可以完全省略显式比较和条件选择,我们最终得出以下结论:

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);
}
float32x4_t vdelta=vdupq_n_f32(增量);
对于(int i=0;i<64;i+=4){
浮动32x4_t vsfx,vabq;
vsfx=vld1q_f32((常量浮点32_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);
}