title: Challenge while optimizing algo by SIMD NEON
body: <p>I am trying to optimize my algorithm in neon SIMD .</p>
  
  <p>Scalar code :</p>
  
  <pre><code>for (int y = 1; y &lt; (height - 1); y++) {
      int height_offs = y * width;
      for (int x = 1; x &lt; (width - 1); x++) {
          dst[height_offs + x] = (
                  src[(height_offs - width) + (x + 1)] -
                  src[(height_offs - width) + (x - 1)] +
                   // current row
                  src[(height_offs)         + (x + 1)] -
                  src[(height_offs)         + (x - 1)] +
                   // next row
                  src[(height_offs + width) + (x + 1)] -
                  src[(height_offs + width) + (x - 1)]
              );
      }
  }
  </code></pre>
  
  <p>But I found that width and height parameter are not constant. These values are varying by outside iteration. For example width =7 /8 /9 /10 /11 /12 /13 (/ means or). So I thought to take reminder like width%4 and will calculate the <code>dst[height_offs + x]</code> for the remaining reminder values. For example if width is 7 means width loop run from 0,1,2,3,4,5,6 .So I can process vector as 0,1,2,3 and remaining 4,5,6 with 7 as copy of 6. But for each reminder value that is 3,2,1 I have to write a separate implementation which will affect the performance and I will loose the befits of SIMD. I want to ask following questions.</p>
  
  <ul>
  <li>Is there any generic implementation I can do to avoid  rewriting the logic for each reminder value (for 3,2 and 1)` </li>
  <li>Is it a good idea to use SIMD here </li>
  </ul>
  
  <p><strong>Note:</strong> I am optimizing Lucas Kanade Algo where I have to do derivative calculation on each pyramid level.Because of this the height and width of the image got changed .So I can not avoid changing values for width and height .</p>
  
  <p>Vector Code: (not working properly.Need to do some changes inside)</p>
  
  <pre><code>uint32x4_t src_vector32x4__prev0,src_vector32x4__prev1,src_vector32x4__prev2;
  uint32x4_t  src_vector32x4__curr0,src_vector32x4__curr1,src_vector32x4__curr2;
  uint32x4_t  src_vector32x4__next0,src_vector32x4__next1,src_vector32x4__next2;
  uint32x4_t s1,s2,s3,add_32x4u;
  int32x4_t dst_vector32x4;
  uint32_t Idx ;
  
  /* Load destination data into the destination vector register. */
  dst_vector32x4 = vld1q_s32(dst);
  for (int32_t y = 1; y &lt; (src_height - 1); ++y) {
  
      int32_t height_offs = y * src_width;
      for (int32_t x = 1; x &lt; (src_width - 1); x+=4) {
          Idx = height_offs + x ;
          src_vector32x4__prev0 = vld1q_u32(&amp;src[(height_offs - src_width) + (x - 1)]); // 00 01 02 03
          src_vector32x4__prev2 = vld1q_u32(&amp;src[(height_offs - src_width) + (x + 1)]); // 02 03 04 05
  
          src_vector32x4__curr0 = vld1q_u32(&amp;src[(height_offs)             + (x - 1)]); // 10 11 12 13
          src_vector32x4__curr2 = vld1q_u32(&amp;src[(height_offs)             + (x + 1)]); // 12 13 14 15
  
          src_vector32x4__next0 = vld1q_u32(&amp;src[(height_offs + src_width) + (x - 1)]); // 20 21 22 23
          src_vector32x4__next2 = vld1q_u32(&amp;src[(height_offs + src_width) + (x + 1)]); // 22 23 24 25
  
          //src_vector32x4__prev1 = vld1q_u32(&amp;src[(height_offs - src_width) + (x)]);   // 01 02 03 04
          //src_vector32x4__curr1 = vld1q_u32(&amp;src[(height_offs)             + (x)]);   // 11 12 13 14
          //src_vector32x4__next1 = vld1q_u32(&amp;src[(height_offs + src_width) + (x)]);   // 21 22 23 24
  
          s1 = vsubq_u32(src_vector32x4__prev2,src_vector32x4__prev0);
          s2 = vsubq_u32(src_vector32x4__curr2,src_vector32x4__curr0);
          s3 = vsubq_u32(src_vector32x4__next2,src_vector32x4__next0);
  
          add_32x4u = vaddq_u32(s1,vaddq_u32(s2,s3));
          dst_vector32x4 = vreinterpretq_s32_u32(add_32x4u);
          /*Store a destination vector into destination buffer*/
          vst1q_s32(&amp;dst[Idx],dst_vector32x4);
      }
  }
  </code></pre>