2016-07-02 4 views
1

場合:ARMネオンのARMv7 SIMD命令の次のforループのネオンコードを書くための方法を比較

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]; 
    } 
} 

私はvbslq_f32を使用しようが、私はそのパラメータを一つずつ構築しなければなりません。 NEONがなぜ仕事をするより便利な方法を提供しないのか?これを行うための良い方法はありますか?

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); 
} 

答えて

2

実際、一度に1レーンの操作を実行することによってベクトル化のポイントを敗北させるのは少しばかげています。それはまたほとんど不必要です。

この:

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); 

はこれを行うだけの愚かな方法です:NEONはなし除算命令を持っていないよう

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

部門は、もう少し厄介ですが、私たちが実際にしないでください汎用部門が必要です。この逆数演算:

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); 
} 
+0

ありがとうございます!それは本当に私にとって正しいことでした。 –

関連する問題