2016-07-02 3 views
1

경우 :ARM 네온하는 ARMv7 SIMD 명령어 다음 루프 네온 코드를 작성하는 방법을 비교

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

사실, 한 번에 한 레인 씩 작업을 수행하여 벡터화 포인트를 없애는 것은 다소 어리 석습니다. 대개는 불필요합니다.

이 :

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

당신을 감사합니다! 그것은 정말로 나에게 옳은 일을했다. –